例外情况-c++; 我试图理解C++中异常的行为。 我编写了以下代码: class A{ public: A(){ }; ~A(){ cout<<"hello"; }; }; int exceptionTest(){ throw "blablabla"; }; int main(){ A sd; int test = exceptionTest(); return 0; }

例外情况-c++; 我试图理解C++中异常的行为。 我编写了以下代码: class A{ public: A(){ }; ~A(){ cout<<"hello"; }; }; int exceptionTest(){ throw "blablabla"; }; int main(){ A sd; int test = exceptionTest(); return 0; },c++,exception,C++,Exception,将不会调用distructor。 有人能告诉我为什么会有不同的行为吗 谢谢, Li您正在抛出异常的事实在这里是不相关的。在第一个示例中,sd是堆栈上存在的对象。当执行退出其作用域时,无论出于何种原因,它都会被销毁。在第二个示例中,sd是指向使用new显式分配的对象的指针。在将指针传递到delete之前,不会销毁此对象;由于您从未这样做,您的程序当前正在泄漏它。一旦变量超出范围,就会自动调用局部变量析构函数。 析构函数从不在指针上调用,所以您必须自己调用它 我注意到,在这种情况下,即使没有人发现异

将不会调用distructor。 有人能告诉我为什么会有不同的行为吗

谢谢,
Li

您正在抛出异常的事实在这里是不相关的。在第一个示例中,
sd
是堆栈上存在的对象。当执行退出其作用域时,无论出于何种原因,它都会被销毁。在第二个示例中,
sd
是指向使用
new
显式分配的对象的指针。在将指针传递到
delete
之前,不会销毁此对象;由于您从未这样做,您的程序当前正在泄漏它。

一旦变量超出范围,就会自动调用局部变量析构函数。 析构函数从不在指针上调用,所以您必须自己调用它

我注意到,在这种情况下,即使没有人发现异常,也会调用distructor

这正是我们所期待的

这种机制是一种RAII结果,它使您“确保”即使出现异常,也会释放资源。例如:

class File
{
   public:
   File( const std::string filename ) : file_handler(file_open( filename )) { } // whatever the implementation

   ~File() { file_close(file_handler); }

   private:
   FileHandler file_handler;
};

void test(){ throw "This is a test"; }


int main()
{
   File file("test.txt");
   test();
   return false;
}
您可以放心,即使抛出,该文件也将被关闭。因此,如果您使用RAII来管理您的资源


这是因为当抛出异常时,直到它得到catch,它会返回到调用堆栈中,如果没有catch,本地对象就会像超出范围时那样被销毁

本标准对此有以下规定:

-9-如果在程序中找不到匹配的处理程序,则调用函数
terminate()
在调用
terminate()
之前,堆栈是否展开由实现定义

因此,您的编译器执行堆栈展开(调用局部函数的析构函数),其他编译器可能不会。例如,使用G++或codepad.org,该程序将输出“hello”



动态分配的对象不会被销毁,除非您显式销毁它们(使用delete或类似方法)。特别是,如果在此期间发生异常,代码可能永远不会到达释放语句。

这不是一个真正的答案,但我可能会澄清在RAII机制的情况下,我从另一个答案和Mike的评论中理解的行为

#include <iostream>

class Bar
{
        public:
        Bar() { std::cout << "Bar constructor" << std::endl; }
        ~Bar() { std::cout << "Bar destructor" << std::endl; }
};

void foo()
{
        throw("Exception");
}

int main()
{
        // Variation, add { to create a new scope
        Bar bar;
        foo();
        // Variation : }
        return 0;
}
这意味着
g++
不会展开堆栈(或者如果我正确理解了“variant”,就让变量超出范围),因此不会调用析构函数

但是,如果捕获到异常:

#include <iostream>

class Bar
{
        public:
        Bar() { std::cout << "Bar constructor" << std::endl; }
        ~Bar() { std::cout << "Bar destructor" << std::endl; }
};

void foo()
{
        throw("Exception");
}

int main()
{
        try
        {
                Bar bar;
                foo();
        }
        catch (...)
        {
                // Nothing here
        }
        return 0;
}

然后恢复正确的行为。

调用的析构函数不是我所期望的(codepad.org也不是这样)。如果抛出未处理的异常,则不需要展开堆栈,程序可以立即调用
terminate()
。不过,在这种情况下,该语言可能允许堆栈展开,asker的编译器也会这样做。-只有当有一个合适的catch子句用于异常时,您才能依赖调用析构函数,对于未捕获的异常,这可能(看起来)会发生,也可能不会发生。这需要从sandard文档进行验证,但我没有。如果你有,你可以告诉我你在哪里读到的?提前谢谢。
Bar constructor
terminate called after throwing an instance of 'char const*'
Aborted
#include <iostream>

class Bar
{
        public:
        Bar() { std::cout << "Bar constructor" << std::endl; }
        ~Bar() { std::cout << "Bar destructor" << std::endl; }
};

void foo()
{
        throw("Exception");
}

int main()
{
        try
        {
                Bar bar;
                foo();
        }
        catch (...)
        {
                // Nothing here
        }
        return 0;
}
Bar constructor
Bar destructor