例外 - c ++

时间:2010-09-14 10:54:29

标签: c++ exception

我试图理解c ++中异常的行为。 我写了以下代码:

class A{
public: 
    A(){
    };
    ~A(){
        cout<<"hello";

    };
};
int exceptionTest(){

    throw "blablabla";
};

int main(){

        A sd;
    int test = exceptionTest();
     return 0;
}

我注意到在这种情况下,即使没有人捕获异常,也会调用析构函数。 如果我将“主要”代码更改为:

 int main(){

            A* sd = new A();
        int test = exceptionTest();
         return 0;
    }

不会调用析构函数。 谁能告诉我不同​​行为的原因是什么?

谢谢, 李

5 个答案:

答案 0 :(得分:8)

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

答案 1 :(得分:4)

该标准在此事上有以下说法:

  

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

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


动态分配的对象在您明确销毁它们之前不会被销毁(使用删除等)。特别是,如果在此期间发生异常,代码可能永远不会到达释放语句。

答案 2 :(得分:2)

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

答案 3 :(得分:2)

  

我注意到在这种情况下,即使没有人捕获异常,也会调用析构函数。

这正是我所期待的。

这种机制是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;
}

您确信即使使用throw也会关闭该文件。因此,如果您使用RAII来管理资源。

那是因为当抛出异常时,它会被捕获,它会返回到调用堆栈中,如果没有catch,则当我们超出范围时,本地对象将被破坏。

答案 4 :(得分:0)

这不是一个真正的答案,但在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++,此代码(未捕获异常)将输出以下内容:

Bar constructor
terminate called after throwing an instance of 'char const*'
Aborted

意味着g++不会展开堆栈(或者让变量超出范围,如果我正确理解“变量”),那么析构函数不会被调用。

但是,如果您发现异常:

#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

并恢复正确的行为。