抛出的(默认)构造函数中的异常保证应该是什么
What should be the exception guarantee in a (default) constructor that throws?
我知道构造函数可能会抛出异常,当发生不好的事情时,这可能是一件好事。但是当构造函数抛出并假设构造函数中的所有资源都得到正确管理(例如使用 RAII)时,哪一个是确切的异常保证(基本、强)?
详细地说,我正在记录我的代码并编写每个成员函数的异常保证(并尝试编写安全异常代码)。
例如,如果我有这样的类:
struct A
{
std::string s;
A()
{
std::vector<int> v(5);
s = "some text";
/* do a lot of fascinating things */
if (error)
throw 1;
}
};
当构造函数抛出时,调用v
和s
的析构函数,对吧?因此,多亏了std::vector
和std::string
的析构函数,A
的构造函数不会泄漏任何资源,然后它至少提供了基本的保证。我说的对吗?
我的问题是:我可以说这个构造函数提供了强有力的保证吗?另外,是否值得记录构造函数的保证?
我的猜测是:它确实有很强的保证。由于对象在尝试构造它之前不存在,并且如果构造函数失败,则无论如何都不会创建对象,因此操作(构造对象)不起作用,并且一切都保留在构造函数开始之前。
如果我的猜测是正确的:
- 当构造函数只提供基本保证而不是强保证时?
你是对的。构造函数修改的唯一对象是 s
和 v
,它们在调用构造函数之前不存在,在异常退出后也不存在。因此没有可观察到的副作用,构造函数提供了强大的异常保证。
构造函数何时可能仅提供基本保证?可能是人为的例子:
class A {
public:
A() {
printf("A is being constructedn");
throw std::runtime_error("oh no!");
}
};
基本保证是相当明显的,但不是强有力的保证,因为有副作用。(创建副作用的另一种方法是修改全局变量。如果构造函数接受参数,可能会发生更有趣的事情。另一个可能是人为的例子:
class B {
public:
A(std::vector<int>&& v): v(std::move(v)), a() {}
private:
std::vector<int> v;
A a;
};
在这里,A
的构造函数在 B::v
已经初始化后抛出,所以后者被销毁。调用方仍然具有有效的向量,但它现在为空。由于所有对象都处于有效状态,因此仍然满足基本保证,但不是强保证。
强保证要求如果构造函数抛出,则程序的(逻辑)状态不会改变(除了有一个异常需要处理)。这意味着,如果在任何失败情况下,通过引用或指针、全局变量等传递到构造函数中的对象都没有被更改(或者在构造函数离开之前回滚发生的任何更改),则构造函数将满足强异常保证。
示例代码中的构造函数不适用于任何此类对象,因此它确实提供了强有力的保证。
仅提供基本保证的构造函数示例是
struct foo {
foo(int &x) : some_resource(10) {
++x;
if(x % 2 == 0) {
throw "something";
}
}
std::vector<int> some_resource;
};
在这种情况下,基本保证得到了满足 - 在所有情况下some_resource
都被清理 - 但强保证不是因为如果抛出异常x
仍然会发生变化。
至于文档,这是一个意见问题,所以YMMV。当然,我通常的目标是提供合理可能的最强保证,并记录一个功能满足强保证或不抛出保证,如果我确定我可以永远保持这个保证。记录基本保证不是必需的,因为所有功能都应该提供它。不提供它的功能有一个错误。
- 是什么导致了Unity 3D中的"错误线程异常"?
- C++异常被捕获延迟,可能导致这种情况的原因是什么?
- C++ 捕获异常后进行清理的标准方法是什么?
- 处理许多自定义异常的最佳方法是什么
- 提出异常并处理C 的某些异常类型的正确方法是什么?
- 在类中抛出异常的最佳方法是什么
- 是什么导致异常输出以及如何修复
- 与Java的InputMismatchException和IOException Handling等效的C++异常处理机制是什么
- 在C++中使用异常的可能的错误处理策略是什么,它们的后果和影响是什么
- 在使用SFML时,我会得到记忆或出于界限异常,这是什么问题
- C++ 异常中的 catch(异常)是什么意思?
- 用作类型或异常规范时"see below"是什么意思?
- procdump.exe显示的异常的含义是什么
- 复制构造函数中出现异常的可能原因是什么
- 控件的CWnd::DefWindowProc上发生Stackloverlow异常的原因是什么
- 异常代码"EXC_I386_GPFLT"的含义是什么?
- 向量::插入的异常安全保证是什么?
- 抛出的(默认)构造函数中的异常保证应该是什么
- C++11 中默认虚拟析构函数的异常规范是什么?
- C++ 我不明白我的异常是什么()行为