Возможный дубликат:
Есть ли разница в С++ между инициализацией копирования и инициализацией присваивания?
Какая разница между
T a(b);
и
T a = b;
и
T a = T(b);
?
Возможный дубликат:
Есть ли разница в С++ между инициализацией копирования и инициализацией присваивания?
Какая разница между
T a(b);
и
T a = b;
и
T a = T(b);
?
T a( b );
- это прямая инициализация, если она не анализирует как объявление функции, и в этом случае это объявление функции.
T a = b;
- это инициализация копии, что означает, что она работает так, как если бы временный объект строился с правой стороны, и что a
затем копируется или в С++ 11 и более поздних версиях, возможно, временный характер.
Компилятор может свободно удалять (удалять) временное + копирование/перемещение, когда это возможно, но конструктор копирования или перемещения, какой бы он ни был логически использован, должен быть доступен, а не explicit
.
Например, в С++ 03 вы не можете скопировать-инициализировать std::ostringstream
, потому что у него нет конструктора копирования. В С++ 11 вы можете скопировать инициализацию ostringstream
, если инициализатор является временным, что приводит к логической конструкции перемещения (которая, как правило, будет устранена, оптимизирована). Например, это объявление инициализации копии,
ostringstream s = ostringstream( "blah" );
& hellip; не компилируется как С++ 03, потому что в С++ 03 инициализация копии вызывает конструктор экземпляра класса, который не существует. Однако он компилируется как С++ 11, потому что в С++ 11 инициализация копии вызывает конструктор перемещения. И хотя (чтобы сохранить иллюзию потока), std::ostringstream
не может быть скопирован напрямую, его можно перемещать.
Другая такая разница: в С++ 03 только синтаксис инициализации копирования поддерживает курсивные инициализаторы фигурных скобок, которые в С++ 03 можно использовать, когда T
является агрегированным типом, таким как необработанный массив. В С++ 11 обозначение фигурных скобок было расширено и обобщено как равномерный синтаксис инициализации, поэтому его можно использовать также с прямой инициализацией. Итак, следующее объявление прямой инициализации,
int v[]{ 3, 1, 4, 1, 5, 9, 2, 6, 5, 4 };
& hellip; не компилируется как С++ 03, но компилируется как С++ 11 и более поздних версий.
Синтаксис инициализации копии =
- это исходный синтаксис инициализации из C.
И в С++ 11 и более поздних версиях из-за семантики перемещения он может использоваться в гораздо более широком диапазоне случаев, чем в С++ 03, например, с std::ostringstream
.
T a(b);
Вызывает конструктор a
, который принимает b
. (Если b
имеет один и тот же тип, тогда вызывается конструктор копирования).
T a = b;
создается временный объект типа T
, создаваемый b
. Затем вызывается конструктор копирования (=
не является назначением в этом случае и в следующем случае!).
T a = T(b);
То же, что и выше! за исключением того, что мы явно создали временный объект.
Обратите внимание, что стандарт позволяет полностью исключить временные копии во втором и третьем случаях. Кроме того, если b
не имеет тип T
, то в первом случае T
не должен иметь конструктор копирования. Во втором и третьем случаях, даже несмотря на то, что реализация вольна оптимизировать все это, для нее по-прежнему требуется доступный конструктор копирования. IIRC стандарт называет это: копировать elision.
Это все вызовы конструктора - знак = это просто синтаксический сахар. Точно, какие конструкторы вызываются в определенной степени до компилятора.
Оператор = будет ссылаться на конструктор копии по умолчанию, если оператор = перегружен. Я считаю, что это сделало бы мелкую копию; присваивая одни и те же значения элемента первому объекту в качестве правого оператора