C++中的对象创建和销毁顺序
Object creation and destruction order in C++
我写了一个简单的程序来学习更多关于在 C++ 中创建和销毁对象的顺序(使用 Visual Studio 2015)。在这里:
#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 个临时对象,但请向我解释 when 和 how many A
实例被创建和销毁?
正如评论中已经指出的那样,当您按值将它们作为参数传递时,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
如您所见,当您将 a1 作为参数传递给 c1 的构造函数时会发生一次复制构造,而当此构造函数初始化其成员 a 时会发生第二次复制构造。临时副本随即被销毁,而成员在 c 被销毁时被销毁。
编辑:
Here 您可以在创建复制构造函数时阅读确切的规则。
为了不创建默认的复制构造函数,提供任何用户定义的构造函数是不够的,它需要是 copy/move-constructor.
编辑2:
取自 C++14 标准(12.8 复制和移动 class 对象):
7 If the class definition does not explicitly declare a copy constructor, one is declared implicitly. If the class definition declares a move constructor or move assignment operator, the implicitly declared copy constructor is defined as deleted; otherwise, it is defined as defaulted (8.4). The latter case is deprecated if the class has a user-declared copy assignment operator or a user-declared destructor.
我写了一个简单的程序来学习更多关于在 C++ 中创建和销毁对象的顺序(使用 Visual Studio 2015)。在这里:
#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 个临时对象,但请向我解释 when 和 how many A
实例被创建和销毁?
正如评论中已经指出的那样,当您按值将它们作为参数传递时,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
如您所见,当您将 a1 作为参数传递给 c1 的构造函数时会发生一次复制构造,而当此构造函数初始化其成员 a 时会发生第二次复制构造。临时副本随即被销毁,而成员在 c 被销毁时被销毁。
编辑:
Here 您可以在创建复制构造函数时阅读确切的规则。
为了不创建默认的复制构造函数,提供任何用户定义的构造函数是不够的,它需要是 copy/move-constructor.
编辑2:
取自 C++14 标准(12.8 复制和移动 class 对象):
7 If the class definition does not explicitly declare a copy constructor, one is declared implicitly. If the class definition declares a move constructor or move assignment operator, the implicitly declared copy constructor is defined as deleted; otherwise, it is defined as defaulted (8.4). The latter case is deprecated if the class has a user-declared copy assignment operator or a user-declared destructor.