RAII捕获构造函数异常的方法

时间:2013-02-05 14:52:32

标签: c++ exception constructor raii

我有一个可以在其构造函数中抛出异常的类。如何在try / catch块中声明该类的实例,同时仍然可以在正确的范围内使用它?

try { MyClass lMyObject; }
catch (const std::exception& e) { /* Handle constructor exception */ }

lMyObject.DoSomething(); // lMyObject not in scope!

是否有另一种方法可以实现这一点,同时尊重RAII成语?

我不想使用init()方法进行两阶段构建。我能想到的另一件事是:

MyClass* lMyObject;

try { lMyObject = new MyClass(); }
catch (const std::exception& e) { /* Handle constructor exception */ }

std::shared_ptr<MyClass> lMyObjectPtr(lMyObject);
lMyObjectPtr->DoSomething();

正常工作,但我对范围和指针间接的原始指针不满意。这只是另一个C ++疣吗?

5 个答案:

答案 0 :(得分:5)

如果构造函数抛出,则意味着对象初始化失败,因此无法启动它。

MyClass* lMyObject;
try { lMyObject = new MyClass(); }
catch (std::exception e) { /* Handle constructor exception */ }

在上面,如果构造函数抛出异常,lMyObject保持未初始化,换句话说,指针包含一个不确定的值。

有关详细说明,请参阅经典Constructor Failures

  

我们可以按如下方式总结C ++构造函数模型:

     

或者:

     

(a)构造函数通常通过到达它的结尾或return语句返回,并且该对象存在。

     

或者:

     

(b)构造函数通过发出异常退出,该对象现在不仅不存在,而且从不存在。

     

没有其他可能性。

答案 1 :(得分:2)

编写代码的最佳方法是: -

MyClass lMyObject; 
lMyObject.DoSomething(); 

没有特洛伊,捕获或指针。

如果构造函数抛出,则无法调用DoSomething。哪个是对的:如果构造函数抛出,则对象从未构造过。

而且,重要的是,不要捕捉(甚至捕获/重新抛出)异常,除非你有一些建设性的东西。让异常完成他们的工作并起作用,直到知道如何处理它们的东西能够完成它的工作。

答案 2 :(得分:1)

构造函数用于将对象置于一致状态并建立类不变量。允许异常转义构造函数意味着该构造函数中的某些内容未能完成,因此现在该对象处于某种未知的奇怪状态(现在也可能包括资源泄漏)。由于对象的构造函数尚未完成,编译器也不会导致它的析构函数被调用。也许您正在寻找的是捕获构造函数中的异常。假设它没有被重新抛出,这将导致构造函数完成执行,并且该对象现在已完全形成。

答案 3 :(得分:0)

您无需使用shared_ptr,请使用unique_ptr

std::unique_ptr<MyClass> pMyObject;
try { pMyObject.reset(new MyClass()); }
catch (std::exception &e) { /* Handle constructor exception */ throw; }
MyClass &lMyObject = *pMyObject;

lMyObject.DoSomething();

显然,您有责任确保程序不会落入catch块,而无需初始化pMyObject或退出该功能(例如通过return或{{1} })。

如果可用,您可以使用Boost.Optional来避免使用堆内存:

throw

答案 4 :(得分:-1)

您可以设置MyClass的复制构造函数来接受垃圾输入,从而有效地声明一个带有对象声明的指针。然后你可以manually call try块中的默认构造函数:

MyClass lMyObject(null); // calls copy constructor
try {
    new (lMyObject) MyClass(); // calls normal constructor
}
catch (const std::exception& e) { /* Handle constructor exception */ }

lMyObject.DoSomething();
相关问题