我有一个设计问题。让我们先说这段代码
struct Trial{
const double a;
Trial(double a_) : a(a_){}
};
int main(){
Trial t1(1.);
Trial t2(2.);
t1 = t2;
}
不编译,因为 Trial::operator=
不是编译器默认构建的,因为 Trial::a
是 const
。这非常明显。
现在重点是,先写代码
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/