【问题标题】:call callback function when object is destroyed对象销毁时调用回调函数
【发布时间】:2015-05-27 03:49:13
【问题描述】:

我正在阅读很久以前写的一些论坛帖子,并遇到了这样的问题:

如何创建一个对象,以便向它传递一个回调函数,并且当对象被销毁时,回调函数总是被执行?

我知道这个回调函数应该放在 RAII 之后的析构函数中。并且有人发布了这个问题的解决方案代码如下

class MyClass {
  public:
    MyClass(void (*cb)()) : done(cb) {}
    ~MyClass() {
      if (done) {
        try {
            (*done)();
        }
        catch (...) {
            // choice of exit, log, throw an alert to somewhere in the 
            //system, or ignore
        }
     }
   }
 private:
 void (*done)();
};

但不知何故,我对这段代码感到不舒服。

  1. 因为通常建议不要在析构函数中使用throw,但至少在这段代码中是否可以,因为整个trycatch 块都在析构函数中?
  2. 不知何故,我觉得在析构函数中取消引用指针是不安全的,因为当已经抛出另一个异常时,指针指向的对象可能在堆栈展开期间处于无效状态。但是在这段代码中,指向的函数是一个成员函数,并且在析构函数中检查了这个指针,那么在这种情况下是否完全可以?
  3. 还有比这段代码更好的解决方案吗?

【问题讨论】:

  • 错了,析构函数回调。
  • "由于指针指向的对象在堆栈展开期间可能处于无效状态,此时已经抛出了另一个异常" - 此示例中的回调仅接受独立函数,而不是对象,因此无需担心对象状态。另一方面,回调可能会在内部访问其他对象,但这是另一回事。
  • @RemyLebeau,你认为如果析构函数调用一个不是类成员的函数指针可以吗?
  • 您还需要注意,当进入析构函数时,对象现在严格属于包含该析构函数的类。这意味着从析构函数调用的任何虚方法都将调用当前类中范围内的虚方法,而忽略派生类中的任何覆盖。
  • @EJP:这与使用回调函数有什么关系?除非调用对象将其 this 指针传递给回调,但本讨论中的示例没有这样做。

标签: c++ exception c++11


【解决方案1】:

规则是不要让任何异常逃脱析构函数。

您的析构函数可以接收异常,甚至抛出异常,前提是它们在析构函数方法结束之前被捕获。所以在结束之前抓住一切。

我认为取消引用 dtor 中的指针没有任何问题。它与任何其他方法相同,具有相同的风险。 (因此请提前计划,以免取消引用 NULL 或无效指针)。

您的代码对我来说看起来不错。
我要指出缺少虚拟 dtor,并且根据详细信息,您可能希望将成员 done 设为 protected 成员而不是 private em>

【讨论】:

    猜你喜欢
    • 2014-08-28
    • 2017-06-03
    • 1970-01-01
    • 2011-05-24
    • 2018-07-24
    • 1970-01-01
    • 1970-01-01
    • 2021-02-26
    • 2010-11-05
    相关资源
    最近更新 更多