вызов деструктора и конструктора копирования .. (почему он вызывается в это время) - PullRequest
2 голосов
/ 06 июня 2010

У меня есть следующий код

#include <iostream>
using namespace std;

class Object {

public:
   Object(int id){
     cout << "Construct(" << id << ")" << endl; 
     m_id = id;       
   }

   Object(const Object& obj){
      cout << "Copy-construct(" << obj.m_id << ")" << endl;  
      m_id = obj.m_id;
   }

   Object& operator=(const Object& obj){
      cout << m_id << " = " << obj.m_id << endl; 
      m_id = obj.m_id;
      return *this; 
   }

   ~Object(){
       cout << "Destruct(" << m_id << ")" << endl; 
   }
private:
   int m_id;

};

Object func(Object var) { return var; }

int main(){
   Object v1(1);
   cout << "( a )" << endl;
   Object v2(2);
   v2 = v1;
   cout << "( b )" << endl;
   Object v4 = v1;
   Object *pv5;
   pv5 = &v1;
   pv5 = new Object(5);
   cout << "( c )" << endl;
   func(v1);
   cout << "( d )" << endl;
   delete pv5;
}

который выводит

Construct(1)
( a )
Construct(2)
2 = 1
( b )
Copy-construct(1)
Construct(5)
( c )
Copy-construct(1)
Copy-construct(1)
Destruct(1)
Destruct(1)
( d )
Destruct(5)
Destruct(1)
Destruct(1)
Destruct(1)

У меня есть некоторые проблемы с этим, во-первых, почему Object v4 = v1; вызывает конструктор копирования и выдает Copy-construct(1) после печати ( b ).

Также после печати ( c ) конструктор копирования снова вызывается дважды? Я не уверен, как эта функция работает для Object func(Object var) { return var; }

и сразу после этого Destruct(1) вызывается дважды, прежде чем печатается ( d ).

извините за длинный вопрос, я запутался с вышесказанным.

Ответы [ 3 ]

4 голосов
/ 06 июня 2010
Object v1(1);
// Construct(1)

Обычный вызов конструктора для автоматической переменной стека (уничтожается в конце функции).

cout << "( a )" << endl;
// ( a )

Object v2(2);
// Construct(2)

Еще один вызов конструктора.

v2 = v1;
// 2 = 1

Оператор присваивания вызван, потому что v2 уже был создан (мы вызвали конструктор для него), и теперь мы присваиваем один существующий объект другому.

cout << "( b )" << endl;
// ( b )

Object v4 = v1;
// Copy-construct(1)

Здесь вызывается конструктор копирования, поскольку объект v4 все еще не создан, поэтому мы создаем его как копию v1. Задание берется здесь, чтобы означать то же самое, как если бы вы сделали Object v4(v1)

Object *pv5;
pv5 = &v1;
pv5 = new Object(5);
// Construct(5)

Вызовите конструктор для объекта кучи (уничтожается явно с помощью delete).

cout << "( c )" << endl;
// ( c )

func(v1);
// Copy-construct(1) <br />
// Copy-construct(1) <br />
// Destruct(1) <br />
// Destruct(1) <br />

Сначала вызывается конструктор копирования для копирования v1 в параметр var. Он вызывается снова, чтобы создать копию var в качестве возвращаемого значения для вызывающей стороны. var уничтожается, поскольку он выталкивается из стека при выходе из функции. Возвращаемое значение уничтожается после выражения func (v1).

cout << "( d )" << endl;
// ( d )

delete pv5;
// Destruct(5)

Объект, на который указывает pv5, уничтожается вручную.

} // end of main
// Destruct(1) <br />
// Destruct(1) <br />
// Destruct(1) <br />

Автоматические переменные v1, v2, v4 (все скопировавшие идентификатор v1 из конструкции присваивания или копирования) извлекаются из стека, и для каждого вызывается деструктор.

2 голосов
/ 06 июня 2010

У меня есть некоторые проблемы с этим, во-первых почему Object v4 = v1; вызвать копию конструктор и производство Copy-construct (1) после печати из (б).

Несмотря на знак =, вы вызываете конструктор копирования здесь. Помните, у вас нет конструктора по умолчанию. Вы создаете новый Object и инициализируете его значением v1. Вы должны были сделать:

cout << "( b )" << endl;
Object v4(0);
v4 = v1;

... вы бы увидели ...

( b )
Construct(0)
0 = 1

... что я думаю, вы ожидали.

Также после печати (с) Копи-конструктор снова вызывается дважды ?, я не уверен, как это функция работает, чтобы произвести этот объект func (Object var) {return var; }

Здесь вы передаете var по значению (а не по ссылке [&]), что означает, что создается копия объекта (один вызов конструктора копирования). Затем вы возвращаете другой объект (опять же, а не ссылка), поэтому необходимо сделать еще одну копию (второй вызов конструктора копирования).

и сразу после этого Destruct (1) получает вызывается дважды, прежде чем (d) будет напечатан.

Те объекты, которые вы только что создали с помощью конструкторов копирования? Они просто вышли из поля зрения, и их деструкторы были вызваны.

Когда вы delete v5, его деструктор называется.

Затем вы достигаете конца своей функции main, и три Object экземпляра, которые вы создали в стеке (v1, v2, v4), достигают конца своего времени жизни и уничтожаются как стек разматывается.

Вы, наверное, уже заметили, что у вас столько же вызовов деструкторов, сколько у вас вызовов конструктора!

1 голос
/ 06 июня 2010

Что касается первого вопроса, Object v4 = v1; является синтаксическим сахаром для Object v4(v1);, который более очевидно вызывает конструктор копирования.

Второй немного сложнее. При передаче переменных по значению в функции, они должны быть скопированы - таким образом, вызов конструктора копирования. Копия объекта также должна быть помещена в стек в месте, где вызывающий может получить к нему доступ, поскольку копия, переданная функции, перестает существовать, когда функция возвращается. После того, как эти две копии сделаны, параметр уничтожается, поскольку он извлекается из стека, а возвращаемое значение уничтожается, потому что его значение не используется. У них одинаковый идентификатор, потому что они являются копиями v1.

...