Ответ 1

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.

Ответ 2

T a(b);

Вызывает конструктор a, который принимает b. (Если b имеет один и тот же тип, тогда вызывается конструктор копирования).

T a = b;

создается временный объект типа T, создаваемый b. Затем вызывается конструктор копирования (= не является назначением в этом случае и в следующем случае!).

T a = T(b);

То же, что и выше! за исключением того, что мы явно создали временный объект.

Обратите внимание, что стандарт позволяет полностью исключить временные копии во втором и третьем случаях. Кроме того, если b не имеет тип T, то в первом случае T не должен иметь конструктор копирования. Во втором и третьем случаях, даже несмотря на то, что реализация вольна оптимизировать все это, для нее по-прежнему требуется доступный конструктор копирования. IIRC стандарт называет это: копировать elision.

Ответ 3

Это все вызовы конструктора - знак = это просто синтаксический сахар. Точно, какие конструкторы вызываются в определенной степени до компилятора.

Ответ 4

Оператор = будет ссылаться на конструктор копии по умолчанию, если оператор = перегружен. Я считаю, что это сделало бы мелкую копию; присваивая одни и те же значения элемента первому объекту в качестве правого оператора