C + + копировать-конструировать конструировать и назначить вопрос - PullRequest
6 голосов
/ 17 марта 2010

Вот выдержка из пункта 56 книги "C ++ Gotchas":

Нередко можно увидеть простой написана инициализация объекта Y любой из трех разных способов, как будто они были эквивалентны.

Y a( 1066 ); 
Y b = Y(1066);
Y c = 1066;

На самом деле, все три из них инициализация, вероятно, приведет в том же объектном коде, являющемся генерируется, но они не эквивалентны. Инициализация известна как прямая инициализация, и это делает именно то, что можно ожидать. инициализация осуществляется через прямой вызов Y :: Y (int).

Инициализация b и c более сложный. На самом деле, они тоже сложный. Это оба копии инициализация. В случае с инициализация б, мы запрашиваем создание анонимного временного типа Y, инициализируется значением 1066. Затем мы используем этот анонимный временный как параметр для копии конструктор для класса Y для инициализации б. Наконец, мы вызываем деструктор для анонимный временный.

Чтобы проверить это, я сделал простой класс с элементом данных (программа прикреплена в конце), и результаты оказались удивительными. Похоже, что для случая 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. Чтобы быть точным, я ожидал, что будет создан пустой объект, а затем объект, который будет создан и назначен для пустого объекта. На практике объекты были созданы конструктором копирования.

Ответы [ 3 ]

16 голосов
/ 17 марта 2010

Синтаксис

X a = b;

, где a и b относятся к типу X, всегда означало копирование Безотносительно вариантов, таких как:

X a = X();

используются, назначения не происходит, и никогда не было. Построить и назначить будет что-то вроде:

X a;
a = X();
6 голосов
/ 17 марта 2010

Компилятору разрешено оптимизировать регистры b и c так, чтобы они совпадали с a. Кроме того, компилятор может полностью исключить вызовы конструкции копирования и оператора присваивания, поэтому все, что вы видите, не обязательно совпадает с различными компиляторами или даже с настройками компилятора.

1 голос
/ 15 сентября 2017

Начиная с C ++ 17, все три из этих эквивалентны (если Y::Y(int) не равно explicit, что просто запретило бы c) из-за того, что часто называют обязательным копия elision .

Даже Y c = 1066; создает только один Y объект, потому что результатом неявного преобразования в Y является значение, которое используется для инициализации c, а не для создания временного.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...