Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/155.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ C++;堆栈对象的构造函数异常处理_C++_Exception_Scope_Stack_Allocation - Fatal编程技术网

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

C++ C++;堆栈对象的构造函数异常处理,c++,exception,scope,stack,allocation,C++,Exception,Scope,Stack,Allocation,如果我希望有一个在构造期间可能抛出的堆栈分配对象,但希望在调用站点处理异常,那么如何使该对象可以从构造它的try块外部访问 乙二醇 如果我将myObj封装在一个try中,那么try范围之外的任何东西都看不到它,但我不想让其他所有东西都在其中,因为这样代码就变成了30层嵌套的try块,这就是异常处理应该使用init函数错误代码的替代方法来移除的 我无法在构造函数内处理异常,因为对异常的反应取决于MyThrowingClass使用的上下文 显然,这个问题可以通过有一个 MyThrowingClass

如果我希望有一个在构造期间可能抛出的堆栈分配对象,但希望在调用站点处理异常,那么如何使该对象可以从构造它的try块外部访问

乙二醇

如果我将myObj封装在一个try中,那么try范围之外的任何东西都看不到它,但我不想让其他所有东西都在其中,因为这样代码就变成了30层嵌套的try块,这就是异常处理应该使用init函数错误代码的替代方法来移除的

我无法在构造函数内处理异常,因为对异常的反应取决于MyThrowingClass使用的上下文

显然,这个问题可以通过有一个

MyThrowingClass* pMyObj;
然后能够包装

pMyObj = new MyThrowingClass();
但这当然也可以通过堆栈分配的对象来实现吗

这是唯一的解决办法

MyThrowingClass myObj;

try {
    myObj.init();
} catch(...) {
//...
}
在这一点上,我们回到了基本上与错误代码一样糟糕的状态,有一个未初始化或部分初始化的对象

请注意,这并不是一个全局对象,我希望有一些东西可以在很多地方实例化

有一个try块包装整个范围(这里是main中的所有内容),并捕获在一个try块的末尾处理每个可能的异常,而不是在其站点附近模糊地处理异常,这真的是理想的解决方案吗

int main() {
try {

//absoultely everything

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

}

}
如何使对象可以从构建它的try块外部访问

如果构造失败,则对象不存在;所以没有什么可访问的

当然,使用堆栈分配的对象也可以实现这一点

自动(即堆栈分配)对象只初始化一次,因此即使处理异常,也无法返回并尝试重新初始化它。如果您确实希望能够重试,那么您必须使用更复杂的方法,比如您建议的动态分配或两阶段初始化。另一种选择是某种
boost::optional
(或者,从明年开始,
std::optional
),它允许您在一个自动存储区内随意创建和销毁对象

拥有一个覆盖整个范围的try块真的是理想的解决方案吗


在典型情况下,如果本地未处理异常,并且初始化失败表示出现不可恢复的错误,则为“是”。在您的特殊情况下,您可以在本地处理它并进行恢复。否。

try
旨在确定可能因某种原因引发的对象的范围。通过绕过它,你绕过了它试图保护你的东西(使用一个定义不好的对象)。考虑使用函数来生成对象。通过使用
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()));
}
如果我希望有一个在构造期间可能抛出的堆栈分配对象,但希望在调用站点处理异常,那么如何使该对象可以从构造它的try块外部访问

基本上,你不能。至于将所有代码包装在一个try块中是一个好主意还是坏主意,这取决于“所有代码”的大小——十几行左右的代码没什么大不了的

如果初始化器抛出,是否确实要调用
MyThrowingClass::doSomethingImportant()
?除非您以某种方式保证修复
catch
中损坏的初始化,否则您将对部分初始化的对象调用方法


将对
doSomethingImportant()
的调用与对象的构造包含在同一个try块中,将为您提供设计异常的确切功能:在出现问题时,跳过以下代码(依赖于前面的代码)到错误处理程序。

理想情况下,您应该将对
myObj
的所有引用放在
try
块中。否则,您的指针解决方案是唯一的选项。好的,这说明了一个极好的观点,即如果初始化失败,堆栈分配的对象不可能再次构造,因此即使有对象失败的信息,您也无法修复它。因此,从对象派生的所有使用都应该在try块中,因为这是确保在您尝试使用该对象时该对象存在的唯一方法。指针初始化的方式可以重试,因此可以在try{}的分数之外使用它。谢谢。我认为这里的关键是@mike seymour指出的:如果构造函数失败,就没有办法修复对象,因此能够从try{}范围之外访问对象是毫无意义/危险的。如果您可以修复它,那么这将使它成为一个理想的特性,就像在指针情况下修复对象是可行的一样。
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()));
}