在C ++中从构造函数中抛出异常

时间:2012-03-10 01:47:25

标签: c++ exception-handling constructor

我在这里阅读了几篇文章,否则可以从构造函数中抛出异常。但是,我注意到,如果从构造函数中抛出异常,它不会调用基类的析构函数或其数据成员。请考虑以下示例:

#include <iostream>
using namespace std;
struct C
{
    C() { cout << __FUNCTION__ << endl;  }
    ~C() { cout << __FUNCTION__ << endl; }
};

struct E: public C
{
    C c;
    E() { cout << __FUNCTION__ << endl; throw 4; }
    ~E() { cout << __FUNCTION__ << endl; }
};

int main()
{
    E e;
}


$ g++ test.cpp; ./a.exe
C
C
E
terminate called after throwing an instance of 'int'
Aborted (core dumped)

在这种情况下,E的构造函数抛出异常,但不会调用C的析构函数作为数据成员或基类。现在,如果C的析构函数执行一些清理操作,如关闭文件/套接字和删除堆分配,这可能会导致问题。

所以我的问题是为什么以及何时可以从构造函数中抛出异常。

4 个答案:

答案 0 :(得分:12)

如果发现错误,将运行析构函数。当在C ++中抛出未捕获的异常时,运行时调用std::terminate。默认情况下,std::terminate会调用std::abort,它们在出路时不会调用析构函数。

使用此版本:

#include <iostream>
using namespace std;
struct C
{
    C() { cout << __FUNCTION__ << endl;  }
    ~C() { cout << __FUNCTION__ << endl; }
};

struct E: public C
{
    C c;
    E() { cout << __FUNCTION__ << endl; throw 4; }
    ~E() { cout << __FUNCTION__ << endl; }
};

int main()
{
    try {
        E e;
    } catch(...) {
    }

    return 0;
}

我得到输出:

C
C
E
~C
~C

答案 1 :(得分:2)

  

我注意到如果从构造函数中抛出异常,它不会调用基类的析构函数或其数据成员

是的,确实如此。

然而,由于整个程序中没有catch该异常,程序会立即终止

如果你要在调用堆栈的某个地方捕获异常,那么将按预期调用基类和成员的析构函数。

答案 2 :(得分:1)

您没有处理“例外”。

> cat test.cpp
#include <iostream>

using namespace std;
struct C
{
    C() { cout << __FUNCTION__ << endl;  }
    ~C() { cout << __FUNCTION__ << endl; }
};

struct E: public C
{
    C c;
    E() { cout << __FUNCTION__ << endl; throw 4; }
    ~E() { cout << __FUNCTION__ << endl; }
};

int main()
{
    try
    {
        E e;
    }
    catch (int i)
    {
        std::cerr << "Handled " << i << std::endl;
    }
}

构建并运行..

> make test
make: `test' is up to date.
> ./test
C
C
E
~C
~C
Handled 4
> 

两个C被破坏,完全正常终止。

答案 3 :(得分:1)

1) E's constructor catched the exception and ran completly.
   Therefore, its object is created and the distructor is 
   invoked.

struct C
{
    C() {cout <<__FUNCTION__<< endl;}
    ~C() {cout <<__FUNCTION__<< endl;}
};

struct E: public C
{
    C c;
    E() { 
    try {
        cout <<__FUNCTION__<< endl; 
        throw 4;
    }
    catch(int i) {
    cerr<<"int "<<i<<" is catched by "<<__FUNCTION__<<endl;
    }   
}
    ~E() {cout << __FUNCTION__ << endl;}
void print(){
    cout<<"obj of class E is created"<<endl;
}
};

int main()
{
    try {
       E e;
   e.print();
} 
catch(int i) {
   cerr<<"int "<<i<<" catched by "<<__FUNCTION__<<" function"<<endl;
    }

    return 0;
}

/*
Results:
C::C
C::C
E::E
int 4 is catched by E::E
obj of class E is created
E::~E
C::~C
C::~C
*/

2) E's constructor didn’t catch the exception and ran incompletly.
   In result, its object is not created. Therefore, its distructor
   is not invoked.

struct C
{
    C() {cout <<__FUNCTION__<< endl;}
    ~C() {cout <<__FUNCTION__<< endl;}
};

struct E: public C
{
    C c;
    E() { 
   try {
      cout <<__FUNCTION__<< endl; 
      throw 4;
   }
   catch(float i) {
      cerr<<"int "<<i<<" is catched by "<<__FUNCTION__<<endl;
   }    
}
    ~E() {cout << __FUNCTION__ << endl;}
void print(){
    cout<<"obj of class E is created"<<endl;
}
};

int main()
{
    try {
        E e;
    e.print();
} 
catch(int i) {
   cerr<<"int "<<i<<" catched by "<<__FUNCTION__<<" function"<<endl;
    }

    return 0;
}

/*
Results:
C::C
C::C
E::E
C::~C
C::~C
int 4 catched by main function
*/