Вот является извлечение из объекта 56 из книги "Глюки C++":
Весьма распространено видеть, что простая инициализация Y возражает записанный любой из трех различных путей, как будто они были эквивалентны.
Y a( 1066 );
Y b = Y(1066);
Y c = 1066;
Фактически, все три из этих инициализаций, вероятно, приведут к тому же сгенерированному объектному коду, но они не эквивалентны. Инициализация известного как прямая инициализация, и это делает точно, что можно было бы ожидать. Инициализация выполняется посредством прямого вызова Y:: Y (интервал).
Инициализации b и c более сложны. На самом деле они слишком сложны. Это оба инициализации копии. В случае инициализации b мы запрашиваем создание анонимного временного файла типа Y, инициализированного со значением 1066. Мы затем используем этот анонимный временный файл в качестве параметра для конструктора копии для класса Y для инициализации b. Наконец, мы называем деструктор для анонимного временного файла.
Для тестирования этого я сделал простой класс с элементом данных (программа, присоединенная в конце), и результаты были неожиданными. Кажется, что для случая c, объект был создан конструктором копии, а не, как предложено в книге.
Кто-либо знает, изменился ли стандарт языка, или это - просто функция оптимизации компилятора? Я использовал Visual Studio 2008.
Пример кода:
#include <iostream>
class Widget
{
std::string name;
public:
// Constructor
Widget(std::string n) { name=n; std::cout << "Constructing Widget " << this->name << std::endl; }
// Copy constructor
Widget (const Widget& rhs) { std::cout << "Copy constructing Widget from " << rhs.name << std::endl; }
// Assignment operator
Widget& operator=(const Widget& rhs) { std::cout << "Assigning Widget from " << rhs.name << " to " << this->name << std::endl; return *this; }
};
int main(void)
{
// construct
Widget a("a");
// copy construct
Widget b(a);
// construct and assign
Widget c("c");
c = a;
// copy construct!
Widget d = a;
// construct!
Widget e = "e";
// construct and assign
Widget f = Widget("f");
return 0;
}
Вывод:
Constructing Widget a
Copy constructing Widget from a
Constructing Widget c
Assigning Widget from a to c
Copy constructing Widget from a
Constructing Widget e
Constructing Widget f
Copy constructing Widget from f
Я был больше всего удивлен результатами построения d и e. Чтобы быть точным, я ожидал, что пустой объект будет создан, и затем объект, который будет создан и присвоен пустому объекту. На практике объекты были созданы конструктором копии.
Синтаксис
X a = b;
где a и b имеют тип X, всегда означал копирование конструкции. Какие бы варианты, такие как:
X a = X();
не использовались, никакого присваивания не происходит, и никогда не происходило. Конструирование и присваивание было бы чем-то вроде:
X a;
a = X();
Компилятору разрешено оптимизировать случаи b
и c
, чтобы они были такими же, как a
. Кроме того, вызовы операторов копирования и присваивания могут быть полностью исключены компилятором в любом случае, поэтому то, что вы видите, не обязательно будет одинаковым для разных компиляторов или даже настроек компилятора.