我在这里阅读了几篇文章,否则可以从构造函数中抛出异常。但是,我注意到,如果从构造函数中抛出异常,它不会调用基类的析构函数或其数据成员。请考虑以下示例:
#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的析构函数执行一些清理操作,如关闭文件/套接字和删除堆分配,这可能会导致问题。
所以我的问题是为什么以及何时可以从构造函数中抛出异常。
答案 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
*/