我有以下代码:
#include <iostream>
#include <vector>
#include <tr1/memory>
struct FooError {};
struct Foo
{
~Foo() { std::cerr << "~Foo() executed" << std::endl; }
explicit Foo(unsigned int index) { if (5 == index) throw FooError(index); };
};
int main() {
typedef std::tr1::shared_ptr<Foo> FooPtr;
std::vector<FooPtr> foos;
for (unsigned int index = 0; index < 20; ++index)
{
try
{
foos.push_back(FooPtr(new Foo(index)));
}
catch (const FooError&)
{
std::cerr << "FooError caught" << std::endl;
}
}
}
当有~Foo()
块时,我看到一组try{} catch{}
被执行。如果没有异常处理程序,则不会打印任何内容。是否意味着在处理异常时会调用堆栈分配对象的析构函数?或者由于std :: cerr缓冲问题而没有打印出来?
答案 0 :(得分:5)
以下是C ++ 03标准的详细信息。
从15.3 / 9处理例外
如果在程序中找不到匹配的处理程序,则调用函数terminate();
从18.6.3异常终止:
实现的默认terminate_handler调用abort()。
从3.6.3 / 4终止:
调用
void abort();
中声明的函数<cstdlib>
终止程序,而不对自动或静态存储持续时间的对象执行析构函数,也不调用传递给atexit()的函数。
这就是为什么你的 foos
对象没有被破坏(它有静态存储持续时间)的原因。但是,即使您更改它以使其成为局部变量(具有自动持续时间),也可能无法解决问题(强调添加):
因此,对于static duration
个对象,除非您更改终止处理程序(可能让它调用exit()
而不是abort()
),否则不会调用析构函数。但是,对于自动对象,仍然存在可能的问题(强调添加):
15.5.1 / 1
terminate()
函数在没有找到匹配处理程序的情况下,它是 实现定义之前是否展开堆栈 调用terminate()。在所有其他情况下,堆栈不得 在调用terminate()之前解开。
答案 1 :(得分:3)
程序的范围展开,无论是通过正常执行还是通过try / throw / catch,只有当应用程序从main
返回时才会退出。如果应用程序通过异常(或通过abort()
或terminate()
)退出,则不会发生展开并且不会调用析构函数。
这适用于自动和静态对象。
答案 2 :(得分:2)
在循环之后,在程序退出之前,正在调用析构函数(来自向量)。
如果没有捕获异常,则调用terminate,在不调用析构函数的情况下中止程序。
答案 3 :(得分:1)
如果捕获异常,将调用deallocators来清理内存。如果您没有发现异常,应用程序将退出。
向量实际上将所有数据存储在堆中;这就是为什么它可以调整大小。您可以将堆栈上的数据视为指向堆上内存的指针(对您隐藏)。