简体   繁体   English

堆栈对象的C ++构造函数异常处理

[英]C++ constructor exception handling for stack object

Given a situation where I want to have a stack allocated object that may throw during construction, but want to handle the exception at the calling site, how do I make the object accessible from outside the try block where it is constructed? 给定一种情况,我想让一个堆栈分配的对象可能在构造过程中抛出,但又想在调用站点处处理异常,如何使该对象从构造它的try块外部可以访问?

Eg 例如

class MyThrowingClass {

MyThrowingClass() {throw exception();}

doSomethingImportant() {
//...
}

};

int main() {

//Need to catch the exception:
try {
MyThrowingClass myObj;
} catch() {
//actually handle the error
//...
}

//Also need to use myObj later on
myObj.doSomethingImportant();//but we can't use it here because it was scoped to the try block...
}

If I have myObj encased in a try then nothing outside the scope of the try can see it, but I don't want to have everything else inside there because then the code becomes 30 levels of nested try blocks, which is what the exception handling is supposed to remove with using the alternative of init function error codes. 如果我将myObj放入try中,则try范围之外的任何内容都看不到,但是我不想在其中包含其他所有内容,因为这样代码就会变成30个嵌套的try块级别,这就是异常处理的内容应该使用替代初始化函数错误代码删除。

I can't handle the exception inside the constructor as the reaction to the exception depends on the context of the use of MyThrowingClass. 我无法在构造函数中处理异常,因为对异常的反应取决于M​​yThrowingClass的使用上下文。

Obviously the problem could be circumvented by having a 显然,可以通过以下方法解决该问题:

MyThrowingClass* pMyObj;

and then being able to wrapper the 然后能够包装

pMyObj = new MyThrowingClass();

but surely this should be achievable with a stack allocated object too? 但是肯定也可以使用堆栈分配的对象来实现吗?

Is the only solution to do something like 是做类似事情的唯一解决方案

MyThrowingClass myObj;

try {
    myObj.init();
} catch(...) {
//...
}

at which point we're back to basically as bad as error codes and having an uninitialised or partially initialised object. 在这一点上,我们又回到了与错误代码一样糟糕的程度,并且拥有未初始化或部分初始化的对象。

Note that this is not intended to be a global object, I want to have something that will be instantiated in many places. 请注意,这并不是要成为全局对象,我想在许多地方都可以实例化某些东西。

Is it really the ideal solution to have a try block that wraps the entire scope (here everything that would be inside main) and catches that handle every possible exception at the end of that one try block as opposed to being able to handle exceptions vaguely near to their site? 确实有一个try块是一个理想的解决方案,它包装了整个作用域(这里将包含在main内的所有内容),并在那个try块的末尾捕获了处理所有可能异常的捕获,而不是能够模糊地处理异常到他们的网站?

int main() {
try {

//absoultely everything

}
catch (exceptionTypeA &a) {
//...
}
catch exceptionTypeB &b) {

}

}

how do I make the object accessible from outside the try block where it is constructed? 如何使对象从构造它的try块外部可以访问?

If construction fails, then the object doesn't exist; 如果构建失败,则该对象不存在;否则,该对象将不存在。 so there's nothing to access. 所以没有东西可访问。

surely this should be achievable with a stack allocated object too? 当然这也应该可以通过堆栈分配的对象来实现吗?

Automatic (ie stack-allocated) objects are only initialised once, so even if you handle the exception, there's no way to go back and try to re-initialise it. 自动(即堆栈分配)对象仅初始化一次,因此即使您处理了异常,也无法返回并尝试重新初始化它。 If you do want to be able to retry, then you'll have to use something more complicated, like the dynamic allocation or two-stage initialisation you propose. 如果确实希望重试,则必须使用更复杂的方法,例如建议的动态分配或两阶段初始化。 Another alternative is something boost::optional (or, from next year, std::optional ), which allows you to create and destroy objects at will within a lump of automatic storage. 另一种选择是boost::optional (或者从明年开始, std::optional ),它使您可以在一次自动存储中std::optional创建和销毁对象。

Is it really the ideal solution to have a try block that wraps the entire scope? 拥有包裹整个作用域的try块真的是理想的解决方案吗?

In the typical case, where exceptions aren't handled locally and initialisation failure indicates an unrecoverable error, yes. 在典型情况下,不是在本地处理异常,并且初始化失败表示发生了不可恢复的错误,是的。 In your special case, where you can handle it locally and recover, no. 在特殊情况下,您可以在本地处理它并进行恢复,没有。

try is designed to scope objects that can throw for a reason. try被设计为作用域可以由于某种原因抛出的对象。 By working around it, you are circumventing that which it's trying to protect you from (using a poorly defined object.) Consider using a function to generate the object. 通过解决它,您正在避开它试图保护您的内容(使用定义不明确的对象)。考虑使用函数来生成对象。 By using a noexcept move constructor, you can guarantee that the move out of the object is safe: 通过使用noexcept move构造函数,可以保证移出对象是安全的:

class MyThrowingClass {
  public:
    MyThrowingClass() {
        throw exception();
    }

    // throw() is *okay* if you don't have noexcept
    MyThrowingClass(const MyThrowingClass && other) noexcept { 
    }

};


MyThrowingClass GetObj() {
    try {
        return std::move(MyThrowingClass());
    } catch(...) {
        // return some well defined default or terminate program
    }
}

int main() {
    MyThrowingClass myObj(std::move(GetObj()));
}

Given a situation where I want to have a stack allocated object that may throw during construction, but want to handle the exception at the calling site, how do I make the object accessible from outside the try block where it is constructed? 给定一种情况,我想让一个堆栈分配的对象可能在构造过程中抛出,但又想在调用站点处处理异常,如何使该对象从构造它的try块外部可以访问?

Basically, you can't. 基本上,你不能。 As for wrapping ALL the code in a try block being a good or bad idea, that depends on the size of "all the code" - a dozen lines or so lines is no big deal. 至于将所有代码包装在try块中是个好主意,这取决于“所有代码”的大小-十几行左右没什么大不了的。

Do you really want to call MyThrowingClass::doSomethingImportant() if the initialiser throws? 如果初始化程序抛出异常,您真的要调用MyThrowingClass::doSomethingImportant()吗? Unless you somehow guarantee to fix the broken initialisation in the catch you're then calling methods on a partially initialised object. 除非您以某种方式保证在catch修复损坏的初始化,否则您将在部分初始化的对象上调用方法。

Including the call to doSomethingImportant() in the same try block as the construction of the object would give you exactly what exceptions are designed to do: in the event of a problem skip past the following code (which is dependent on the preceding code) to an error handler. 在与对象的构造相同的try块中包含对doSomethingImportant()的调用将为您提供确切的异常设计:在出现问题时,跳过以下代码(取决于前面的代码)以错误处理程序。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM