是否应将范围对象(在构造函数和析构函数中实现的互补逻辑)用于资源清理(RAII)?
或者我可以用它来实现应用程序逻辑的某些方面吗?
前段时间我问过Function hooking in C++。事实证明Bjarne addressed this problem和他提出的解决方案是创建一个实现operator->
的代理对象并在那里分配一个范围对象。 “before”和“after”分别在作用域对象的构造函数和析构函数中实现。
问题是析构函数不应该抛出。所以你必须将析构函数包装在try { /* ... */ } catch(...) { /*empty*/ }
块中。这严重限制了处理“后”代码中错误的能力。
是否应将范围对象用于清理资源,还是可以将其用于更多资源?我在哪里划线?
答案 0 :(得分:4)
如果您迂腐地考虑RAII的definition,那么使用范围规则和析构函数调用不涉及资源释放的任何操作都不是RAII。
但是,谁在乎呢?也许你真正要问的是,
每次离开功能 Y 时,我都希望 X 发生。是吗 滥用使用相同的作用域规则和析构函数调用 如果 X 不是资源释放,RAII在C ++中使用?
我说,不。抓一点,我说没有。实际上,从代码清晰度的角度来看,如果有多个返回点或可能有异常,最好使用析构函数调用来执行代码块。我会记录这样一个事实:你的对象在破坏时做了一些非显而易见的事情,但在实例化时这可能是一个简单的注释。
你在哪里划线?我认为KISS原则可以指导你。您可以在析构函数的主体中编写整个程序,但会滥用。无论如何,你的蜘蛛侠会告诉你这是一个坏主意。保持代码尽可能简单,但并不简单。如果表达某些功能的最自然的方式是在析构函数的主体中,那么在析构函数的主体中表达它。
答案 1 :(得分:2)
您希望保证始终完成后缀的方案。这听起来就像RAII对我的工作。然而,我并不一定以这种方式写它。我宁愿使用模板化成员函数的方法链。
答案 2 :(得分:1)
我认为使用C ++ 11,您可以半安全地允许suffix()
调用。严格的规则不是“永远不会从析构函数中抛出”,尽管这是一个很好的建议,而是the rule is:
在处理另一个析构函数时,永远不会从析构函数中抛出异常 例外
在析构函数中,您现在可以使用std::current_exception
,我认为它会验证析构函数+异常规则中的“在处理另一个异常时”元素。有了这个,你可以这样做:
~Call_proxy() {
if (std::current_exception()) {
try {
suffix();
}
catch(...) {
// Not good, but not fatal perhaps?
// Just don't rethrow and you're ok
}
}
else {
suffix();
}
}
我不确定这在实践中是否真的是一个好主意,但是如果在抛出另一个异常的过程中抛出它还有一个难以处理的问题。
至于“它是否滥用”我不认为它是滥用元文字或编写a?b:c
而不是完整的if
声明,如果它是正确的工具!它并没有颠覆任何语言规则,只是在法律条文中利用它们。真正的问题是对不熟悉代码和长期可维护性的读者的行为的可预测性,但这是所有设计的问题。