それだけでなく文法も複雑が過ぎるのだ。
参考:
throw
この場合はどうなるだろうか。
#include <iostream>
#include <stdexcept>
class PA {
public:
PA( void ){ std :: cout << "PA constructor" << std :: endl; };
~PA( void ){ std :: cout << "PA destructor" << std :: endl; };
};
class PB {
public:
PB( void ){ throw std :: runtime_error("PB constructor error"); };
~PB( void ){ std :: cout << "PB destructor" << std :: endl; };
};
class C {
PA* _pa;
PB* _pb;
public:
C( void ) :
_pa( new PA() )
, _pb( new PB() )
{ std :: cout << "C constructor " << std :: endl; }
~C( void ){
delete _pa;
delete _pb;
std :: cout << "C destructor" << std :: endl;
}
};
int main( void ) {
try{
C c;
}
catch( std :: exception& e ){
std :: cout << e.what() << std :: endl;
}
return 0;
}
PB( void ){ throw std :: runtime_error("PB constructor error"); };
PB
のコンストラクタが例外を投げている。 C
のコンストラクタ的には
PA
の new
が成功してから PB
のコンストラクタが実行されるが、実行結果
PA constructor
PB constructor error
Program ended with exit code: 0
やはり PA
が開放されない。
関数監視ブロック(function-try-block)
こんな構文があるとは知りませんでした。 プログラミング言語C++ ( アスキーアジソンウェスレイシリーズ―Ascii Addison Wesley programming series )をよく読むと、確かに書いてあります。
class Foo { public: Foo try : bar_() { } catch(...) { // コンストラクタで例外が発生したよ // (初期化リストの例外もcatch!) // コンストラクタの場合に限り、自動的に例外が再throwされます } void foo() try { // do something } catch(...) { // 関数fooで例外が発生したよ } private: Bar bar_; };
コレを利用しなければならないようだ。
class PA {
public:
PA( void ){ std :: cout << "PA constructor" << std :: endl; };
~PA( void ){ std :: cout << "PA destructor" << std :: endl; };
};
class PB {
public:
PB( void ){ throw std :: runtime_error("PB constructor error"); };
~PB( void ){ std :: cout << "PB destructor" << std :: endl; };
};
class C {
PA* _pa;
PB* _pb;
public:
C( void ) try :
_pa( new PA() )
, _pb( new PB() )
{
std :: cout << "C constructor " << std :: endl;
}
catch( std :: exception& e ){
delete _pa;
//delete _pb; //not allocated error
std :: cerr << "C constructor error" << std :: endl;
throw;
}
~C( void ){
delete _pa;
delete _pb;
std :: cout << "C destructor" << std :: endl;
}
};
int main( void ) {
try{
C c;
}
catch( std :: exception& e ){
std :: cout << e.what() << std :: endl;
}
return 0;
}
C( void ) try :
_pa( new PA() )
, _pb( new PB() )
{
std :: cout << "C constructor " << std :: endl;
}
catch( std :: exception& e ){
delete _pa;
//delete _pb; //not allocated error
std :: cerr << "C constructor error" << std :: endl;
throw;
}
利用したとして今度は PB
が new
されていないので delete
できない。
new
されたかを何かしらで確認しなければならない、が、
ひとまずエラーを捕捉することはできた。実行結果
PA constructor
PA destructor
C constructor error
PB constructor error
Program ended with exit code: 0
やはりスマートポインタが一番の解決策か。
#include <iostream>
#include <stdexcept>
class PA {
public:
PA( void ){ std :: cout << "PA constructor" << std :: endl; };
~PA( void ){ std :: cout << "PA destructor" << std :: endl; };
};
class PB {
public:
PB( void ){ throw std :: runtime_error("PB constructor error"); };
~PB( void ){ std :: cout << "PB destructor" << std :: endl; };
};
class C {
std :: unique_ptr< PA > _pa;
std :: unique_ptr< PB > _pb;
public:
C( void ) try :
_pa( new PA() )
, _pb( new PB() )
{
std :: cout << "C constructor " << std :: endl;
}
catch( std :: exception& e ){
std :: cerr << "C constructor error" << std :: endl;
throw;
}
~C( void ){
std :: cout << "C destructor" << std :: endl;
}
};
int main( void ) {
try{
C c;
}
catch( std :: exception& e ){
std :: cout << e.what() << std :: endl;
}
return 0;
}
class C {
std :: unique_ptr< PA > _pa;
std :: unique_ptr< PB > _pb;
public:
C( void ) try :
_pa( new PA() )
, _pb( new PB() )
{
std :: cout << "C constructor " << std :: endl;
}
catch( std :: exception& e ){
std :: cerr << "C constructor error" << std :: endl;
throw;
}
~C( void ){
std :: cout << "C destructor" << std :: endl;
}
};
メンバクラスを std :: unique_ptr
に変更しながら、関数監視ブロックを利用した。
これでデストラクタも問題なく呼ばれ、エラーも捕捉できるはず。実行結果
PA constructor
PA destructor
C constructor error
PB constructor error
Program ended with exit code: 0
大丈夫だ。スマートポインタは正義。
throw
について