当时我正在阅读谷歌C++风格指南( Google ),并在例外情况部分感到困惑。根据指南,使用它的缺点之一是:
异常安全需要RAII和不同的编码实践。为了使编写正确的异常安全代码变得容易,需要大量的支持机器。此外,为了避免要求读者理解整个调用图,异常安全代码必须隔离将写入持久状态的逻辑写入“提交”阶段。这将带来好处和成本(可能是您被迫混淆代码以隔离提交)。允许例外情况会迫使我们总是支付这些费用,即使它们不值得
具体来说,我不明白的说法是:
(...)异常安全代码必须将写入持久状态的逻辑隔离到“提交”阶段。
这是:
(...)也许您被迫混淆代码来隔离提交(.)。
我想我不习惯术语“持久状态”、“提交阶段”、“混淆代码来隔离提交”。这将是很好的一些小的解释,例子或参考这些术语,可能是为什么这是正确的。
发布于 2010-07-22 19:30:33
“写入持久状态”的意思大致是“写入文件”或“写入数据库”。
“进入‘提交’阶段。”的意思大致是“一次完成所有的写作”。
“也许您被迫混淆代码以隔离提交”的意思大致是“这可能会使代码难以阅读”(稍微误用“混淆”一词意味着故意使某些内容难以阅读,而在这里它们的意思是无意中使其难以阅读,但这种误用可能是故意的,以达到戏剧性的效果)
详细说明:“写入到持久状态”更紧密地意味着“向某些永久媒体写出重新创建该对象所需的所有有关该对象的详细信息”。如果写入被异常中断,那么那些“写出的详细信息”(即“持久状态”)可能包含一半新状态和一半旧状态,从而导致在重新创建对象时出现无效对象。因此,写入状态必须作为一个不可中断的行为来完成。
发布于 2010-07-22 19:23:12
基本上,现代C++使用范围绑定资源管理(SBRM,或RAII)。也就是说,对象清理其析构函数中的资源,保证调用该资源。
这一切都很好,除非你的代码不是现代的。例如:
int *i = new int();
do_something(i);
delete i;如果do_something抛出一个异常,那么您已经泄漏了。正确的解决办法是在野外没有这样的资源,即:
std::auto_ptr<int> i(new int());
do_something(i.get());现在它再也不能泄漏了(而且代码更干净!)
我认为指南想要说的是,我们已经有了所有这些旧代码,而使用一种现代风格将花费太多的精力。所以我们不要使用异常。(我不想修改所有的代码.我非常不喜欢谷歌风格指南。)
发布于 2010-07-22 19:42:54
持久状态的含义是:即使您正在使用RAII,并且您的对象被正确地销毁,允许您清理,如果try块中的代码以某种方式修改了系统的状态,您很可能需要弄清楚如何回滚这些更改,因为操作没有成功完成。它们在这里使用术语commit,因为它与事务有关,即当您执行一个操作时,系统的状态应该是100%成功完成或根本没有完成。
以下是即使与RAII在一起也会搞砸的原因:
struct MyClass
{
MyClass(Foo* foo)
{
m_bar = new Bar;
foo->changeSomeState();
}
~MyClass()
{
delete m_bar;
}
Bar* m_bar;
};现在,如果您有以下代码:
try
{
MyClass myClass(foo);
Baz baz;
baz.doSomething(); // Throws an exception
}
catch(...)
{
// MyClass doesn't leak memory, but should it try to undo
// the change it made to foo?
}因此,要正确处理这种情况,您必须添加更多代码,将其作为事务处理,并在抛出异常时回滚try块中对持久状态所做的任何更改。他们只是说强迫事务语义会使代码混乱(混淆)。
我不同意禁止例外,顺便说一句,只是想表明他们指的是什么问题。
https://stackoverflow.com/questions/3312513
复制相似问题