c++ - 在设计时未考虑异常安全的方法/类中提供强有力的保证

标签 c++ exception error-handling

我有一个设计问题。让我们先说这段代码

struct Trial{
    const double a;
    Trial(double a_) : a(a_){}
};

int main(){
    Trial t1(1.);
    Trial t2(2.);
    t1 = t2;
}

不编译,因为 Trial::operator= 不是编译器默认构建的,因为 Trial::aconst。这非常明显。

现在重点是,先写代码

struct Trial{
    const double a;
    Trial(double a_) : a(a_){}
};

struct MyClass : private Trial{
    MyClass(double a_) : Trial(a_), i(0) {};
    void wannaBeStrongGuaranteeMemberFunction(){
        MyClass old(i);
        bool failed = true;
        //... try to perform operations here
        if(failed)
            *this = old;
    }
    unsigned int i;
};

int main(){
    MyClass m1(1.);
    m1.wannaBeStrongGuaranteeMemberFunction();
}

我需要为一个派生自Trial的类的一些方法提供强异常安全性。此类方法对无穷无尽的成​​员系列(示例中的 i)执行无穷无尽的系列操作,这使得“手动”恢复操作变得不切实际。因此,我决定最好对整个类进行复制,如果有任何失败,再将其复制回来。

小括号,代码只是示例。在遗留的现实世界代码中,一切都复杂得多。 在此示例中,仅复制 i 就可以了,但在实际代码中并非如此。 此外,操作具有多个(且复杂的)执行路径,因此将它们“读取”为“交易”将是一件痛苦的事情。 此外,我正在使用作用域守卫来实现这一点,因此在实际代码中可以正确管理异常。

当然,由于 *this = old 行,整个程序无法编译。

您将如何解决问题/解决问题?

最佳答案

显而易见的答案是修改 Trial 使其支持 任务也是如此。除此之外,如果唯一的原因是你 要支持任务就是提供强有力的保障, 您可以实现自己的赋值运算符,最好 private,它忽略了基类;因为你知道 两个基类将是相同的,不需要分配 他们之间。

请注意,强保证比 任务。这不会改变问题:你不能交换 Trial 的两个版本。你很可能有 像这样的东西:

class MyClass : private Trial
{
    class Protected
    {
        bool myCommitted;
        MyClass* myOwner;
        MyClass myInstance;
    public:
        MyClass( MyClass& owner )
            : myCommitted( false )
            , myOwner( &owner )
            , myInstance( owner )
        {
        }
        ~MyClass()
        {
            if ( myCommitted ) {
                myOwner->swap( myInstance );
            }
        }
        MyClass& instance() { return myInstance; }
        void commit() { myCommitted = true; }
    };

public:

    void protectedFunc()
    {
        Protected p( *this );
        p.instance().unprotecedVersionOfFunc();
        //  ...
        p.commit();
    }

任何异常都会使对象保持不变。 (你可以, 当然,反转逻辑,对 this 进行修改, 如果未提交则交换。)做事的好处 这种方式是您还将“撤消”内存中的任何更改 分配等

最后:你真的想在 Trial 中使用 const 成员吗? 实现这个的通常方法是制作 a 非常量但私有(private),并且只提供一个 setter/getter 。这意味着 Trial::a 实际上是 const,除了 是完整的 作业。

关于c++ - 在设计时未考虑异常安全的方法/类中提供强有力的保证,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18013358/

相关文章:

java - 我应该声明一个未经检查的异常吗?

sql - 我无法在 PrestaShop v1.6.1.0 中添加产品

vbscript - 如何忽略VBScript中的Internet错误?

c++ - 通过多个键对大 vector 进行预排序并存储映射

c++ - 为什么 virtual void test()=00 有效但 virtual void test()=+0 和 virtual void test()=-0 无效?

java - 验证构造函数输入的最佳位置

batch-file - 使用管道运算符时出现错误时批处理脚本终止

python - 如何在python中的子流程中使用错误处理

c++ - gcc -Wstringop-overflow 在这里提示什么?

C++ #include 导致 'duplicate symbols'