8

Рассмотрим следующий код:конструктор копирования не вызывается при инициализации объекта с обратным значением функции

#include <iostream> 

using namespace std; 

class A 
{ 
    public: 
     int a; 
     A(): a(5) 
     { 
      cout << "Constructor\n"; 
     } 
     A(const A &b) 
     { 
      a = b.a; 
      cout << "Copy Constructor\n"; 
     } 
     A fun(A a) 
     { 
      return a; 
     } 
}; 

int main() 
{ 
    A a, c; 
    A b = a.fun(c); 
    return 0; 
} 

Выход указанного выше кода с g++ file.cpp составляет:

Constructor 
Constructor 
Copy Constructor 
Copy Constructor 

Выходной сигнал выше код с g++ -fno-elide-constructors file.cpp является:

Constructor 
Constructor 
Copy Constructor 
Copy Constructor 
Copy Constructor 

Я знаю, что возвращаемое значение Optimiz ция. Мой вопрос в том, какой вызов вызывает копирование конструктора (временный объект при возврате или возвращенный объект, скопированный в b)?

Если конструктор с включенной копией является тем, который используется для создания b, то как вообще создается b (потому что в этом случае также нет вызова конструктора)?

Если я заменю строку A b = a.fun(c); на a.fun(c) и скомпилирую с использованием первого метода или даже второго метода, то и конструктор копирования вызывается 2 раза. Итак, если в случае, описанном в предыдущем абзаце, конструктор копирования временного объекта удаляется, то почему в этом случае он не отклоняется?

+0

Как рассмотрел этот материал, когда я узнал об этом, это был «std :: cout <<» Копировальный конструктор: «<< (void *) b <<" to "<< (void *) this << std :: endl;' , и 'std :: cout <<« Построение »<< (void *) этого << std :: endl'. Бонусные точки, если вы добавляете ходы в C++ 11. – IdeaHat

ответ

6
#include <iostream> 

using namespace std; 

class A 
{ 
public: 
    int a; 
    A(): a(5) 
    { 
     cout << "Constructing: " << (void *)this << std::endl; 
    } 
    A(const A &b) 
    { 
     a = b.a; 
     cout << "Copy Constructor: " << (void *)this << " from " << (void *)&b << std::endl; 
    } 
    A fun(A a) 
    { 
     return a; 
    } 
}; 

int main() 
{ 

    A a, c; 
    A b = a.fun(c); 

    std::cout << "a:" << (void *)&a << std::endl << 
       "b:" << (void *)&b << std::endl << 
       "c:" << (void *)&c << std::endl; 
    return 0; 
} 

Урожайность:

Constructing: 0x7fffbb377220 
Constructing: 0x7fffbb377210 
Copy Constructor: 0x7fffbb377230 from 0x7fffbb377210 
Copy Constructor: 0x7fffbb377200 from 0x7fffbb377230 
a:0x7fffbb377220 
b:0x7fffbb377200 
c:0x7fffbb377210 

Так строит a, строит c, копирует c до промежуточного (аргумент a функции), а затем копирует промежуточное звено непосредственно в b, пропуская типичное копирование a до возврата промежуточный. Это еще лучше продемонстрировано, если вы передаете по значению (изменение A fun(const A& a):

Constructing: 0x7fff8e9642b0 
Constructing: 0x7fff8e9642a0 
Copy Constructor: 0x7fff8e964290 from 0x7fff8e9642a0 
a:0x7fff8e9642b0 
b:0x7fff8e964290 
c:0x7fff8e9642a0 

конструирует, с конструируются, с копируются непосредственно б, несмотря на б не передаются удовольствия

4

Скопированная копия является копией временного возвращаемого значения в b. Без разрешения возвращаемое значение инициализируется от a и копируется в b. Вместо этого временное, которое в противном случае удерживало бы возвращаемое значение, равно , построенное в b и инициализированное a. [Class.copy]/31:

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

вы можете наблюдать это, если добавить дополнительный выход в fun:

A fun(A a) 
{ 
    cout << "fun!" << endl; 
    return a; 
} 

Затем с элизии вы получите

[...]
удовольствие!
Конструктор копирования

И без:

[...]
весело!
Копирование Конструктор
Конструктор копирования

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