1

Я написал простую программу, чтобы узнать больше о порядке создания и уничтожения объектов на C++ (с использованием Visual Studio 2015). Вот оно:Порядок создания и уничтожения объектов в C++

#include <iostream> 
#include <string> 

using namespace std; 

class A 
{ 
public: 
    A(string name) 
     : name(name) 
    { 
     cout << "A(" << name << ")::constructor()" << endl; 
    } 
    ~A() 
    { 
     cout << "A(" << name << ")::destructor()" << endl; 
    } 
private: 
    string name; 
}; 

class C 
{ 
public: 
    C(string name, A a) 
     : name(name), a(a) 
    { 
     cout << "C(" << name << ")::constructor()" << endl; 
    } 
    ~C() 
    { 
     cout << "C(" << name << ")::destructor()" << endl; 
    } 
private: 
    string name; 
    A a; 
}; 

class B 
{ 
public: 
    B(string name) 
     : name(name) 
    { 
     cout << "B(" << name << ")::constructor()" << endl; 
    } 
    ~B() 
    { 
     cout << "B(" << name << ")::destructor()" << endl; 
    } 
private: 
    string name; 
    A a1{"a1"}; 
    A a2{"a2"}; 
    C c1{"c1", a1}; 
    A a3{"a3"}; 
}; 

int main() 
{ 
    B b("b1"); 
    return 0; 
} 

Выход удивил меня немного (в a1 ы):

A(a1)::constructor() 
A(a2)::constructor() 
C(c1)::constructor() 
A(a1)::destructor() 
A(a3)::constructor() 
B(b1)::constructor() 
B(b1)::destructor() 
A(a3)::destructor() 
C(c1)::destructor() 
A(a1)::destructor() 
A(a2)::destructor() 
A(a1)::destructor() 

Чтобы узнать больше о том, что происходит, я добавил информацию о случаях объектов:

A(string name) 
     : name(name) 
    { 
     cout << "A(" << name << ")::constructor(), this = " << this << endl; 
    } 
    ~A() 
    { 
     cout << "A(" << name << ")::destructor(), this = " << this << endl; 
    } 

результат был еще более удивительным:

A(a1)::constructor(), this = 0039FB28 
A(a2)::constructor(), this = 0039FB44 
C(c1)::constructor() 
A(a1)::destructor(), this = 0039F8A8 
A(a3)::constructor(), this = 0039FB98 
B(b1)::constructor() 
B(b1)::destructor() 
A(a3)::destructor(), this = 0039FB98 
C(c1)::destructor() 
A(a1)::destructor(), this = 0039FB7C 
A(a2)::destructor(), this = 0039FB44 
A(a1)::destructor(), this = 0039FB28 

А именно, почему конструктор a1 называется только один раз и деструктор 3 раза? Я прохожу a по значению, поэтому, очевидно, создается хотя бы 1 временный объект, но, пожалуйста, объясните мне , когда и СколькоA экземпляров создаются и уничтожаются?

+5

Вы не аннотировали многие из других конструкторов своего класса, поэтому вы видите только частичную картину. –

+0

@KerrekSB Вы имеете в виду распечатку значений 'this' для классов B и C?Или что? – NPS

+0

Компилятор добавляет некоторые конструкторы по умолчанию, которые вы не видите. – Galik

ответ

5

Как уже отмечалось в комментариях, объекты типа A также построены путем копирования-построения, когда вы передаете их в качестве аргументов по значению. Для того, чтобы убедиться в этом вы можете добавить копию-конструктор по своему усмотрению: выход

A(const A& other) 
: name(other.name) 
{ 
    cout << "A(" << name << ")::copy-constructor(), this = " << this << endl; 
} 

Пример:

A(a1)::constructor(), this = 0xbff3512c 
A(a2)::constructor(), this = 0xbff35130 
A(a1)::copy-constructor(), this = 0xbff350e8 
A(a1)::copy-constructor(), this = 0xbff35138 
C(c1)::constructor() 
A(a1)::destructor(), this = 0xbff350e8 
A(a3)::constructor(), this = 0xbff3513c 
B(b1)::constructor() 
B(b1)::destructor() 
A(a3)::destructor(), this = 0xbff3513c 
C(c1)::destructor() 
A(a1)::destructor(), this = 0xbff35138 
A(a2)::destructor(), this = 0xbff35130 
A(a1)::destructor(), this = 0xbff3512c 

Try it online

Как вы можете видеть, один экземпляр-строительная происходит, когда вас передать a1 как параметр конструктору c1, а второй - когда этот конструктор инициализирует свой член a. Временная копия немедленно уничтожается, а элемент разрушается, когда c разрушается.

Edit:
Here вы можете прочитать точные правила, когда создается копия-конструктор.
Чтобы не создавать конструктор-конструктор по умолчанию, недостаточно указать какой-либо определяемый пользователем конструктор, он должен быть конструктором copy/move-constructor.

Edit2:

Взятые из C++ 14 стандарта (12.8 Копирование и перемещение объектов класса):

7 Если определение класса не явно объявить конструктор копирования, один объявлен неявно. Если определение класса объявляет конструктор перемещения или перемещает оператор присваивания, неявно объявленный конструктор копирования определяется как удаленный; в противном случае он определяется как дефолт (8.4). Последний случай устарел, если класс имеет пользовательский оператор присваивания копии или объявленный пользователем деструктор.

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