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 S):

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你是指打印出B和C类的'this'值吗?或者是什么? – NPS

+0

编译器正在添加一些你看不到的默认构造函数。 – Galik

回答

5

正如评论中已经指出的那样,A类型的对象也是通过copy-construction构造的,当您将它们作为参数传递给值时。为了看到这一点,你可以自己添加一个拷贝构造函数:

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被销毁时,临时副本立即被破坏,而成员被破坏。

编辑:
Here您可以阅读确切规则创建一个拷贝构造函数时。
为了不创建默认的复制构造函数,仅提供任何用户定义的构造函数是不够的,它需要是复制/移动构造函数。

EDIT2:

从C++ 14标准(12.8复制和移动类对象)摘自:

7如果类定义不明确地声明拷贝构造函数,一个被声明含蓄。如果类定义声明了移动构造函数或移动赋值操作符,则隐式声明的拷贝构造函数被定义为删除;否则,它被定义为默认(8.4)。如果类具有用户声明的复制赋值运算符或用户声明的析构函数,则不推荐使用后一种情况。