C++堆栈对象的构造函数异常处理
C++ constructor exception handling for stack object
鉴于我希望有一个可能在构造期间抛出的堆栈分配对象,但希望在调用站点处理异常,如何使对象从构造它的 try 块外部访问?
例如
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...
}
如果我将 myObj 封装在 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
中损坏的初始化,否则您将在部分初始化的对象上调用方法。
在与对象构造相同的 try 块中包含对 doSomethingImportant()
的调用将准确地为您提供异常的设计目的:如果出现问题,请跳过以下代码(依赖于前面的代码)到错误处理程序。
- std::string 构造函数如何处理固定大小的 char[]?
- 如何编写移动构造函数以处理非初始化的移动
- 如何使用unique_ptr声明调用构造函数并处理程序终止信号
- 智能指针和构造函数异常
- 构造函数C++异常说明符
- 是否可以对构造函数抛出异常的对象进行异常处理,该对象的异常处理接近其基于堆栈的代码创建
- 如何使用move构造函数正确处理shared_ptr的映射
- boost::archive::text_iarchive构造函数异常
- C++堆栈对象的构造函数异常处理
- 默认构造函数C++异常不会引发吗?
- 如何与命名构造函数一起处理不可复制的成员
- 构造函数中处理的异常已传播回.怎样
- 当函数中静态变量的构造函数异常终止时会发生什么
- 移动构造函数:如何处理容器属性
- 在c++中,如果基类构造函数异常,则构造函数和析构函数的顺序可以是这样
- 如何捕获构造函数异常
- C++构造函数异常处理
- 捕获构造函数异常的RAII方法
- 默认复制构造函数是否处理常量
- Std::unique_ptr::reset和构造函数异常