【发布时间】:2013-08-02 09:27:57
【问题描述】:
我有一个设计问题。先说这段代码
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这一行。
您将如何解决问题/解决问题?
【问题讨论】:
-
疯狂的想法:
this->~MyClass(); new (this) myClass(old); -
@StefanoFalasca 你需要include
<new>。 -
@jrok 非常疯狂。如果副本通过异常退出会发生什么?你留下了一个你不能调用析构函数的对象。如果是本地对象,你就完蛋了,如果是动态分配的,你不能删除它,所以至少,你有内存泄漏。
-
重点是placement new调用的复制构造函数可能会抛出,此时*this的析构函数已经被调用。
-
@StefanoFalasca 我明确指出:如果您因异常离开复制构造函数会发生什么。您已经破坏了对象,但还没有重建它,因此如果没有未定义的行为(可能还有实践中的各种问题),您无法再次破坏它。
标签: c++ exception-handling error-handling