C++ 当对象超出范围时是否调用析构函数?
例如:C++ 当对象超出范围时是否调用析构函数?,c++,destructor,dynamic-memory-allocation,C++,Destructor,Dynamic Memory Allocation,例如: int main() { Foo *leedle = new Foo(); return 0; } class Foo { private: somePointer* bar; public: Foo(); ~Foo(); }; Foo::~Foo() { delete bar; } 编译器会隐式调用析构函数还是内存泄漏 我是动态内存新手,所以如果这不是一个可用的测试用例,我很抱歉。确实会有内存泄漏。会调用超出范围的对象(Foo*
int main() {
Foo *leedle = new Foo();
return 0;
}
class Foo {
private:
somePointer* bar;
public:
Foo();
~Foo();
};
Foo::~Foo() {
delete bar;
}
编译器会隐式调用析构函数还是内存泄漏
我是动态内存新手,所以如果这不是一个可用的测试用例,我很抱歉。确实会有内存泄漏。会调用超出范围的对象(Foo*)的析构函数,但不会调用指向对象(分配的Foo)的析构函数 从技术上讲,由于您处于主状态,因此它不是内存泄漏,因为您可以在应用程序未终止之前访问每个分配的变量。在这方面,我引用Alexandrescu(从现代C++,关于单体的章节) 分配累积数据并丢失所有数据时,会出现内存泄漏 对它的引用。这里的情况并非如此:没有任何东西在积累, 我们将有关分配内存的知识保存到 应用此外,所有现代
当然,这并不意味着您不应该调用
delete
,因为这将是一种非常糟糕(而且危险)的做法。在这种情况下,当main返回程序结束时,操作系统将处理释放所有资源的问题。例如,如果这是任何其他函数,则必须
使用delete。是,如果对象超出范围,将调用析构函数但是 不,在这种情况下不会调用析构函数,因为在作用域中只有一个指针,该指针没有特定的析构函数,因此不会间接调用
Foo
的析构函数
此示例是智能指针的应用领域,如std::unique_ptr
和std::shared_ptr
。这些是实际的类,与原始指针不同,它们有一个析构函数,(有条件地)对指向的对象调用delete
顺便说一句,
Foo
的析构函数删除bar
,但是bar
从未初始化,也没有分配给指向实际对象的地址,因此delete调用将给出未定义的行为,可能会崩溃。首先注意,代码不会编译new
返回指向堆上分配的对象的指针。你需要:
int main() {
Foo *leedle = new Foo();
return 0;
}
现在,由于
new
使用动态存储而不是自动分配对象,因此在函数结束时它不会超出范围。因此,它也不会被删除,并且您已经泄漏了内存。是的,自动变量将在封闭代码块的末尾被销毁。但是继续读下去
您的问题标题询问当变量超出范围时是否调用析构函数。大概你想问的是:
Foo的析构函数会在main()的末尾被调用吗
根据您提供的代码,这个问题的答案是否定的,因为Foo对象具有动态存储持续时间,我们将很快看到
请注意自动变量是什么:
Foo* leedle = new Foo();
这里,leedle
是将被销毁的自动变量leedle
只是一个指针。leedle
指向的东西没有自动存储持续时间,不会被销毁。因此,如果您这样做:
void DoIt()
{
Foo* leedle = new leedle;
}
您泄漏了new leedle
分配的内存
您必须
删除
已分配给新的
的任何内容:
void DoIt()
{
Foo* leedle = new leedle;
delete leedle;
}
通过使用智能指针,这变得更加简单和健壮。在C++03中:
void DoIt()
{
std::auto_ptr <Foo> leedle (new Foo);
}
在本例中,所有变量都具有自动存储持续时间。b
和d
都将在第2行销毁<代码>n将在第1行销毁
2:静态:具有静态存储持续时间的变量将在程序开始前分配,并在程序结束时销毁
3:动态:使用动态内存分配功能(例如,新建
)分配时,将分配具有动态存储持续时间的变量;使用动态内存分配功能(例如,删除
)销毁时,将销毁该变量
在我上面的原始示例中:
void DoIt()
{
Foo* leedle = new leedle;
}
leedle
是一个具有自动存储持续时间的变量,将在末尾销毁。leedle
指向的对象具有动态存储持续时间,并且不会在上面的代码中被销毁。您必须调用delete
来取消分配它
C++11还增加了第四个存储持续时间:
4:线程:线程开始时分配具有线程存储持续时间的变量,线程结束时解除分配。否,您需要自己调用
delete leedle
。标题中的问题为“是”,正文中的问题为“否”。您必须手动删除所有新增内容。如果在构造函数中使用new
(前提是没有引发异常),则可以在析构函数中调用delete
,它将为您清理内存。您的代码甚至无效。请阅读一本C++书——这是一个基本问题,在很多时候都是这样。阅读一些关于RAII的信息,使用智能指针(SyddypTR,UnqyGypTR等等)。可能的副本可能会有点复杂。抱歉,我在写文章的时候错误地提交了,但是你不能仅仅依靠OS来为你做所有的工作。1.向明显的新手传授不良做法。另外,C++标准并不保证OS会回收资源,或者OS甚至存在。即使这样,OS也可能只是简单地调用调用析构函数来恢复内存。保证OS将释放所有内存,但是,这不是当前问题的主题。如果一个在GPU和操作系统上拥有资源的对象刚刚回收了内存,因为它不能保证它会调用任何析构函数,甚至不知道它们的存在,那么vidmem中将发生内存泄漏。请停止使用outmod
void Foo()
{
bool b = true;
{
int n = 42;
} // LINE 1
double d = 3.14;
} // LINE 2
void DoIt()
{
Foo* leedle = new leedle;
}