NPS*_*NPS 1 c++ object-construction temporary-objects object-destruction
我写了一个简单的程序来了解更多关于在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;
}
Run Code Online (Sandbox Code Playgroud)
输出让我感到惊讶(a1s):
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()
Run Code Online (Sandbox Code Playgroud)
要了解有关正在发生的事情的更多信息,我添加了有关对象实例的信息:
A(string name)
: name(name)
{
cout << "A(" << name << ")::constructor(), this = " << this << endl;
}
~A()
{
cout << "A(" << name << ")::destructor(), this = " << this << endl;
}
Run Code Online (Sandbox Code Playgroud)
结果更令人惊讶:
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
Run Code Online (Sandbox Code Playgroud)
也就是说,为什么a1构造函数只被调用一次而析构函数被调用3次?我传递a的值,从而显着至少1个临时对象被创建,但请向我解释的时候和有多少 A被创建和销毁实例?
正如在注释中已经指出的那样,A当你通过值传递它们作为参数时,类型的对象也通过复制构造来构造.为了看到这个,你可以自己添加一个拷贝构造函数:
A(const A& other)
: name(other.name)
{
cout << "A(" << name << ")::copy-constructor(), this = " << this << endl;
}
Run Code Online (Sandbox Code Playgroud)
样本输出:
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
Run Code Online (Sandbox Code Playgroud)
如您所见,当您将a1作为参数传递给c1的构造函数时会发生一个复制构造,而当此构造函数初始化其成员a时会发生第二个复制构造.之后立即销毁临时副本,同时在c被破坏时构件被破坏.
编辑:
在这里,您可以在创建复制构造函数时阅读确切的规则.
为了不创建默认的拷贝构造函数,提供任何用户定义的构造函数是不够的,它需要是一个复制/移动构造函数.
EDIT2:
取自C++ 14标准(12.8复制和移动类对象):
7如果类定义未显式声明复制构造函数,则会隐式声明一个.如果类定义声明了移动构造函数或移动赋值运算符,则隐式声明的复制构造函数被定义为已删除; 否则,它被定义为默认值(8.4).如果类具有用户声明的复制赋值运算符或用户声明的析构函数,则不推荐使用后一种情况.