删除者的调用上下文

Deleter's calling context

与标准智能指针一起使用的 C++ Deleter 是否可以确定调用它的上下文?

假设释放我的资源可能会产生错误。

如果我的资源在堆栈展开期间被释放,我显然不希望我的 Deleter 在出现错误时抛出异常。但是如果使用reset()调用了Deleter,那么向我代码的用户报错就可以了。

struct MyDeleter
{
  typedef ... pointer;

  void operator ()(pointer p)
  {
    if (release_p_failed)
    {
      if (throwing_exception_is_ok)
        throw ...;
      else
        hide_error_to_not_abort;
    }
  }
};

例子

{
  std::unique_ptr<..., MyDeleter> p{ ..., MyDeleter };

  // A:
  p.reset(); // User intends to handle the error. Throwing exception is ok.

  // B: Leave scope and do not throw an exception in case of an error.
}

不,unique_ptr 不提供任何方法来确定删除器的调用上下文。

在这种情况下,您需要提供单独的清理逻辑。

您可以使用std::uncaught_exception()来区分正常销毁和堆栈展开。

如果您担心在堆栈展开期间抛出异常,您应该使用 std::uncaught_exception,例如

struct MyDeleter
{
  typedef ... pointer;

  void operator ()(pointer p)
  {
    if (release_p_failed)
    {
      if (!std::uncaught_exception())   // no stack unwinding in progress
        throw ...;
      else
        hide_error_to_not_abort;
    }
  }
};

如果您需要从任何析构函数中抛出,这是使用的标准习惯用法。 当然,这不能区分是从std::unique_ptr::~std::unique_ptrstd::unique_ptr::reset()调用的。

请注意,从 C++17 开始,std::uncaught_exception 已被弃用并被 std::uncaught_exceptions 取代,返回当前未捕获异常的数量 'in the air'。