我对 c++ 中的范围和内存管理有疑问。这是我遇到麻烦的情况:
Abc function f()
{
Abc c;
return c;
}
Abc d = f();
if(d) cout << "hi";
它会说“嗨”吗?我的意思是......在 f() 中创建的 Abc 不是动态的(我们没有编写新的)......但是我们正在返回值,所以我们保持对对象的引用。它是否有价值,或者一旦超出其范围就会死亡?
谢谢!
#include <iostream>
using std::cout;
using std::endl;
class Abc
{
int m_value = 0;
public:
Abc()
{
cout << "Default Constructor" << std::endl;
}
Abc(const Abc& _source)
{
cout << "Copy Constructor" << std::endl;
//copy stuff
}
Abc& operator=(const Abc& _source)
{
cout << "assignment operator" << std::endl;
if (this == &_source)
return *this;
//copy stuff
return *this;
}
Abc(const Abc&& _source)
{
cout << "Move Constructor" << std::endl;
//move stuff
}
Abc& operator=(const Abc&& _source)
{
cout << "move assignment operator" << std::endl;
//move stuff
return *this;
}
~Abc()
{
cout << "Destructor"<< std::endl;
}
void setValue(int _value)
{
m_value = _value;
}
int getValue()
{
return m_value;
}
};
Abc f()
{
Abc c;
c.setValue(100);
cout << "c value: " << c.getValue() << endl;
return c;
}
int main()
{
Abc d = f();
cout << "d value: " << d.getValue() << endl;
d.setValue(200);
cout << "d value: " << d.getValue() << endl;
}
这是输出:
默认构造函数
c值:100
d 值:100
d 值:200
析构函数
从这里您可以看到编译器足够聪明,可以重用分配的对象而无需制作任何哑副本(C++98/03,C++11 相同的输出)。
使用 MinGW(GCC 4.7.1)编译。
在你的情况下,不可能做出准确的陈述,在下面的第二种情况下:
Abc* function f()
{
Abc *c = new Abc();;
return c;
}
Abc* d = f();
if(d) cout << "hi";
是的,它会说“嗨”,不同之处在于,在第一种情况下,c 保存在堆栈中,而在第二种情况下,它保存在堆中。在您的情况下,键入 if(d) 不是检查对象是否处于活动状态的好方法,因为它是在堆栈上定义的。
为了检查你的情况,你可以在 Abc 的析构函数中添加一个日志,看看它是否会被命中。您将观察到当您使用 f() 返回对象时调用了 Abc 的析构函数。但这并不意味着对象已经死了。只有它的析构函数被调用。但在这种情况下,您不能正确使用析构函数。这就是为什么选择指向对象的指针而不是直接定义它们的原因之一。
Abc f()
{
Abc c;
return c;
}
创建c
type Abc
,复制它并从函数返回(NRVO
可以省略复制)。
Abc d = f();
if(d) cout << "hi";
d
使用 function 的返回值创建并复制初始化它f
。什么是Abc
类型?如果它有operator bool
(或者operator T()
可以T
隐式转换为bool
) - 可能会打印“hi”。