【发布时间】:2018-06-09 23:38:32
【问题描述】:
我编写了以下简短代码进行实验,并尝试在对象调用其构造函数和析构函数时获得“第一手”体验:
class Foo
{
public:
Foo(int bar)
{
this->bar = bar;
std::cout << "Standard constructor called" << std::endl;
}
~Foo()
{
std::cout << "Standard destructor called" << std::endl;
}
Foo(const Foo &foo)
{
std::cout << "Copy constructor called" << std::endl;
this->bar = foo.bar;
}
inline int get_bar() { return bar; }
private:
int bar;
};
Foo make_foo(int bar)
{
Foo f1(bar);
std::cout << "About to return foo with address of: " << &f1 << std::endl;
return f1;
}
int main()
{
Foo f2 = make_foo(3);
std::cout << "New variable has address of: " << &f2 << std::endl;
std::cout << "And a value of " << f2.get_bar() << std::endl;
}
但是当我运行这段代码时,我觉得奇怪的事情发生了。像预期的那样,打印“标准构造函数调用”并打印该函数中 foo 的地址。但是当函数结束时,没有调用析构函数,并且 f2 实际上与 f1 具有相同的内存地址,尽管根据我的理解,f1 应该超出范围并释放其内存,因为它在堆栈上,对吧?或者这不是这种情况下的预期结果?
我的期望是调用复制构造函数将 f1 复制到 f2,然后调用 f1 的析构函数,而 f2 将占用不同的内存地址。
如果有人好奇,这是实际输出:
Standard constructor called
About to return new foo with address of: 0x7fff518e5a88
New variable has address of: 0x7fff518e5a88
And a value of 3
Standard destructor called
有趣的是,当我将make_foo 的返回类型更改为引用类型时,函数几乎按照我的预期执行,f1 被破坏,f2 复制垃圾数据。
这是一些特殊情况,堆栈上的变量在返回分配给另一个我应该注意的变量时不会释放其内存?
【问题讨论】:
-
这是一个返回值优化(RVO)的实例。
f1是在返回值的位置构造的,因为这就是它真正的用途。 -
存在复制省略,这在所有 C++ 标准中都是允许的,并且(C++11 及更高版本)在许多情况下特别需要。