2013-05-25 1 views
9
#include <iostream> 
using namespace std; 

class Y { 
public: 
    Y(int) { 
     cout << "Y(int)\n"; 
    } 
    Y(const Y&) { 
     cout << " Y(const Y&)\n"; 
    } 
}; 

int main() { 
    Y obj1 = 2; // Line 1 
} 

Выход: Y (целое)Почему конструктор копирования не вызывается, чтобы скопировать временный объект на новый определенный объект

Ожидаемый результат: Y (целое) Y (Const Y &)

Вопрос> Основываясь на моем понимании, строка 1 сначала создаст временный объект Y (2), а затем назначит временному объекту obj1. Таким образом, я ожидаю, что вызываются как Y(int), так и Y(const Y&). Но вывод vs2010 сообщает только первый (то есть Y(int)). Зачем?

ответ

10

Почему?

Поскольку при определенных условиях (указанных в пункте 12.8/31 из C++ 11 стандарта на) вызовы конструктора копирования или перемещения конструктора могут быть опущены, даже если эти специальные функции (или деструктор) имеют побочные эффекты:

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

- [...]

- когда объект временного класса, который не был привязан к ссылке (12.2), будет скопирован/перемещен объекту класса с тем же CV-неквалифицированным типом, операция копирования/перемещения может быть опущена , временный объект непосредственно в мишень опущенным копирования/перемещения

- [...]

Это единственное исключение из так называемого правила «как если бы», который обычно ограничивает тип преобразований (оптимизаций), которые компилятор может выполнять в программе, чтобы сохранить свое наблюдаемое поведение.

Обратите внимание, что приведенный выше механизм называется copy elision - даже если это вызов для выполняемого конструктора перемещения.

3

Это называется copy initialization. Y(int) - конструктор преобразования. что

одним параметром конструктора, который объявлен без функции спецификатора явного

компилятор имеет право игнорировать дополнительную копию и использовать conversion constructor.Это означает,

Y obj1 = 2; // Line 1 

эквивалентно

Y obj1(2); // Line 1 
+0

См. Ответ Стефано для дальнейшего обсуждения (Энди правильно). «Явный», вызывающий ошибку, означает, что они никоим образом не эквивалентны. – chris

+3

Инициализация копирования не эквивалентна прямой инициализации. Первый концептуально достигается путем создания временного из инициализирующего выражения ('2'), а затем перемещение-построение или копирование' obj1' из этого временного. Тем не менее, компилятору разрешено выполнять этот вызов конструктору перемещения или конструктору копирования в 12.8/31 (см. Мой ответ) –

4

Это происходит потому, что конструктор имеет только один параметр, и он не отмечен explicit, поэтому компилятор автоматически включается:

Y obj1 = 2; 

В:

Y obj1(2); 

Чтобы предотвратить такое поведение, используйте:

explicit Y(int) { 
    cout << "Y(int)\n"; 
} 

(и компиляция потерпит неудачу в вашем случае).

+1

Тот факт, что 'explicit' вызывает ошибку компилятора, означает, что он не волшебным образом превращает' = 2' в ' (2) '. Все «явные» - это предотвращение неявных преобразований вашего типа. – chris

+0

Добавить явное будет неверным. – q0987

+0

_ ", чтобы предотвратить это поведение [...] и компиляция завершится неудачно в вашем случае." _ –

Смежные вопросы