std :: vector init с двойными скобками вызывает конструктор копирования

Почему, когда я инициализирую std :: vector с фигурными скобками

std::vector<TS> vec {ts1, ts2};

Вызов компилятора дважды, копирование конструктора оператора? С другой стороны — с push_back он вызывается только один раз.

#include <iostream>
#include <vector>
using namespace std;

struct TS{
TS(){
cout<<"default constructor\n";
}

TS(const TS &other) {
cout<<"Copy constructor\n";
}

TS(TS &&other) noexcept{
cout<<"Move constructor\n";
}

TS& operator=(TS const& other)
{
cout<<"Copy assigment\n";
return *this;
}

TS& operator=(TS const&& other) noexcept
{
cout<<"Move assigment\n";
return *this;
}

~TS(){
cout<<"destructor\n";
}

};

int main() {
TS ts1;
TS ts2;
cout<<"-----------------------------------------\n";
std::vector<TS> vec {ts1, ts2};
//vec.push_back(ts1);
//vec = {ts1, ts2};
cout<<"-----------------------------------------\n";return 0;
}

http://ideone.com/qcPG7X

2

Решение

Из того, что я понимаю, initializer_listвсе передать по константной ссылке. Это, вероятно, не безопасно move от одного. initializer_list конструктор vector будет копировать каждый из элементов.

Вот несколько ссылок:
initializer_list и переместить семантику

Нет, это не будет работать так, как задумано; вы все равно получите копии. Я красивая
удивлен этим, так как я думал, что initializer_list существовал для
держите множество временных, пока они не переместились.

начало и конец для initializer_list возвращают const T *, поэтому результат
двигаться в вашем коде T const && — неизменная ссылка. такие
выражение не может быть осмысленно перенесено из. Это будет связывать с
параметр функции типа T const & потому что значения действительно связывают с константой
lvalue ссылки, и вы все равно увидите семантику копирования.

Безопасно ли перемещать элементы списка инициализатора?

initializer_list предоставляет только постоянный доступ к своим элементам. Вы могли бы
используйте const_cast для компиляции этого кода, но тогда шаги могут закончиться
с неопределенным поведением (если элементы initializer_list
действительно постоянны). Так что нет, это не безопасно делать это перемещение. Есть
Обходные пути для этого, если вам действительно это нужно.

Можно ли инициализировать списком вектор типа только для перемещения?

Синопсис в 18.9 делает это достаточно ясно
что элементы списка инициализатора всегда передаются через
Const ссылка. К сожалению, похоже, что
использование move-semantic в элементах списка инициализатора в текущем
пересмотр языка.

вопросы по дизайну std :: initializer_list

Из раздела 18.9 стандарта C ++:

Объект типа initializer_list обеспечивает доступ к массиву объектов типа const E. [Примечание: пара указателей или указатель плюс
длина была бы очевидным представлением для initializer_list.
initializer_list используется для реализации списков инициализаторов, как указано
в 8.5.4. Копирование списка инициализатора не копирует базовый
элементы. — конец примечания]

Я думаю, что причина большинства этих вещей в том, что
std :: initializer_list на самом деле не является контейнером. Не имеет
семантика значения, она имеет семантику указателя. Что становится очевидным
последняя часть цитаты: копирование списка инициализатора не
скопируйте базовые элементы. Видя, как они были предназначены исключительно для
цель инициализации вещей, я не думаю, что это удивительно
что вы не получите все тонкости более надежных контейнеров, таких как
кортежи.

Если я правильно понимаю последнюю часть, это означает, что для initializer_list не копирует базовые элементы. (Предыдущая цитата актуальна только если вы пытаетесь использовать initializer_list без копирования элементов.)

Какова основная структура std :: initializer_list?

Нет, вы не можете перейти от элементов initializer_list, так как
элементы initializer_list должны быть неизменными (см.
первое предложение приведенного выше абзаца). Это также причина
почему только функции-члены с константой дают вам доступ к
элементы.


Если вы хотите, вы можете использовать emplace_back:

vec.emplace_back(TS());
vec.emplace_back(TS());
vec.push_back(std::move(ts1));
vec.push_back(std::move(ts2));
2

Другие решения

Потому что у вас есть два элемента.

1