const в конструкторе копирования в c ++ - PullRequest
10 голосов
/ 14 ноября 2011
class x  
{  
    int a;  
public:  
    x()  
    {  
         cout<<"\n\ndefault constructor";  
    }  
    x(x& obj)  
    {  
         cout<<"\n\ncopy constructor";  
    }  
    x fun()  
   {  
      x ob;  
      return ob;  
    }  
};  
int main()  
{  
    x ob1;  
    x ob2=ob1.fun();  
    return 0;  
 }  

изначально этот код выдавал ошибку "нет подходящей функции для вызова 'x :: x (x)'", когда я изменил конструктор копирования на

x(const x& obj)  
{  
    cout<<"\n\ncopy constructor";  
}  

, вывод становится

конструктор по умолчанию

конструктор по умолчанию
все еще конструктор копирования не выполняется .... почему?

Ответы [ 5 ]

14 голосов
/ 14 ноября 2011

Это называется copy-elision, выполняемым компилятором, и это разрешено спецификацией языка.

Посмотреть эту запись вики:

Что касается того, почему неконстантная версия выдает ошибку компиляции, потому что obj1.fun() возвращает временный объект, который не может быть привязан к неконстантной ссылке, но может связываться с константной ссылкой, поэтому константная версия компилируется нормально. Как только вы сделаете ссылку константной, она будет использоваться только для семантической проверки, но компилятор оптимизирует код, исключая вызов конструктора копирования.

Однако, если вы скомпилируете его с опцией -fno-elide-constructors с GCC, то удаление копии не будет выполнено, и будет вызван конструктор копирования. Документ GCC говорит,

-fno-Elide-конструкторы

Стандарт C ++ позволяет реализации исключать создание временного объекта, который используется только для инициализации другого объекта того же типа. Указание этой опции отключает эту оптимизацию и заставляет G ++ вызывать конструктор копирования во всех случаях.

3 голосов
/ 14 ноября 2011

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

1 голос
/ 14 ноября 2011

Ваш вызов конструктора копирования был пропущен из-за оптимизации разрешения копирования.Вы не можете полагаться на любое наблюдаемое поведение в конструкторе копирования, такое как операторы print.Если вы хотите увидеть выходные данные, попробуйте отключить оптимизации.

1 голос
/ 14 ноября 2011

Первая ошибка была из-за того, что он пытался использовать конструктор копирования с временным объектом.

ob1.fun();  // This returns an x by value

Таким образом, при его использовании слышать

x ob2=ob1.fun();       // You are passing it by value which requires a local temporary
// This is equivalent to this:
x  ob2(obj1.fun());    // So it is trying to do a copy construction.

Временные привязки могут быть связаны толькочтобы констатировать ссылки.Таким образом, он не может скомпилироваться.

После того, как вы исправите эту проблему (с временной), теперь он может использовать конструктор копирования.Но компилятору разрешено оптимизировать его, если это возможно.Он не мог оптимизировать его, потому что ему даже не разрешалось использовать его в первой версии.

1 голос
/ 14 ноября 2011

Временные значения являются r-значениями и не привязываются к непостоянным ссылкам. Поэтому ob1.fun() не может привязаться к конструктору x::x(x&).

Однако, значения do связываются с константой ссылками.

Что касается отсутствия выходных данных: конструктор копирования является частным случаем в стандарте, и компилятору разрешено исключать вызовы конструктора копирования, даже если конструктор копирования имеет побочные эффекты. Тем не менее, конструкция должна быть действительной! Другой пример - если вы объявите конструктор копирования explicit - он все равно будет исключен, но ваш код будет ошибочным.

В GCC вы можете сказать -fno-elide-constructors, чтобы вернуть ваш конструктор.

...