【发布时间】:2017-05-07 17:17:06
【问题描述】:
我试图了解在为堆栈上分配的对象分配新值时出现的一些奇怪行为(对于同一数据集,析构函数被调用两次)。我将从代码 sn-p 及其输出开始:
class Foo {
public:
Foo(const string& name) : m_name(name) {
log("constructor");
}
~Foo() {
log("destructor");
}
void hello() {
log("hello");
}
private:
string m_name;
void log(const string& msg) {
cout << "Foo." << this << " [" << m_name << "] " << msg << endl;
}
};
int main() {
{
Foo f {"f1"};
f.hello();
f = Foo {"f2"};
f.hello();
}
cout << "scope end" << endl;
}
输出:
Foo.0x7fff58c66a58 [f1] constructor
Foo.0x7fff58c66a58 [f1] hello
Foo.0x7fff58c66a18 [f2] constructor
Foo.0x7fff58c66a18 [f2] destructor
Foo.0x7fff58c66a58 [f2] hello
Foo.0x7fff58c66a58 [f2] destructor
scope end
我预期会发生什么:
- 0x...58 在堆栈上创建/初始化
- 0x...18 在堆栈上创建/初始化
- Foo 析构函数在 0x...58 被调用(使用 f1 数据)
- Foo 析构函数在 0x...18 被调用(使用 f2 数据)
实际发生的情况:
- 0x...58 在堆栈上创建/初始化
- 0x...18 在堆栈上创建/初始化
- 来自 0x...18 (f2) 的数据被复制到 0x...58
- Foo 析构函数在 0x...18 被调用(使用 f2 数据)
- Foo 析构函数在 0x...58 处被调用(也带有 f2 数据)
所以最后,Foo 析构函数被调用两次以获取相同的数据 (f2)。显然我错过了一些关于它在内部如何工作的东西,所以有人可以指出我正确的方向吗?
【问题讨论】:
-
您不会看到
"f1"析构函数的消息,因为您复制了一个临时对象,该对象将f持有的名称从"f1"更改为"f2"。因此,您首先会看到临时的"f2"破坏,然后是原始实例(现在名为"f2")的破坏。注意数据不一样;它是具有相同值的副本。 -
如果你的类有析构函数,它几乎肯定也应该有一个拷贝构造函数和赋值运算符。
-
还有(可能)一个移动构造函数和移动赋值运算符(“五规则”)。
标签: c++