如何仅对删除器使用 shared_ptr?

How to use a shared_ptr for the deleter only?

我只是想使用 shared_ptr 的删除功能而不使用 shared_ptr 部分。比如,我想在 shared_ptr 超出范围并且删除器不需要传递给它的任何指针时调用一个函数。

我有这个,但是很俗气。

shared_ptr<int> x(new int, [&](int *me) { delete me; CloseResource(); }); 

有没有办法不将任何指针与 shared_ptr 相关联?

更新:根据许多建议,unique_ptr 方式如下所示:

unique_ptr<int, std::function<void(int*)>> x(new int, [&](int *me) {delete me; CloseResource();});

坦率地说,这看起来比 shared_ptr 版本更糟糕,实际上 'better' 。

更新:对于那些喜欢使用这个简单的作用域关闭函数调用者的人,我让它变得更简单了,你甚至不需要分配或释放对象:

shared_ptr<int> x(NULL, [&](int *) { CloseResource(); });

如果你想要一个类似 RAII 的带有 lambda 的语义,也许像这样的东西可以完成这项工作?

namespace details {
  enum class ScopeExitDummy { };
}


template<typename T>
class scope_exit_t
{
public:
  inline scope_exit_t(T&& codeChunk_)
    : m_codeChunk(std::forward<T>(codeChunk_)) {
  }

  inline scope_exit_t(scope_exit_t<T>&& rhs_)
    : m_codeChunk(std::move(rhs_.m_codeChunk))
  {
  }

  ~scope_exit_t() {
    m_codeChunk();
  }

private:
  T m_codeChunk;
};

template<typename T>
inline scope_exit_t<T> operator+(details::ScopeExitDummy, T&& functor_) {
  return scope_exit_t<T>{std::forward<T>(functor_)};
}

#define AtScopeExit auto TW_UNIQUE_VARIABLE(_scopeExit) = details::ScopeExitDummy{} + [&]

用法如下:

AtScopeExit {
  CloseResource();
};

注意:TW_UNIQUE_VARIABLE只是一个宏,它生成一个唯一的变量名,这样代码就不会与手写的声明冲突。

#define TW_STR_CONCAT_IMPL(x, y) x##y
#define TW_STR_CONCAT(x, y) TW_STR_CONCAT_IMPL(x, y)

#ifdef __COUNTER__
  #define TW_UNIQUE_VARIABLE(prefix) TW_STR_CONCAT(prefix, __COUNTER__)
#else
  #define TW_UNIQUE_VARIABLE(prefix) TW_STR_CONCAT(prefix, __LINE__)
#endif

听起来您 可能 想做的是将 "delete" 责任移交给 "somebody else",这样您就不必再担心了。如果是这种情况,使用自定义删除器的 unique_ptr(不是 shared_ptr)将起作用:

struct Foo final {};
Foo* New() { return new Foo; }
void Delete(Foo* p) { delete p; }

int main()
{
    auto p = New();
    std::unique_ptr<Foo, decltype(&Delete)> up(p, &Delete);
}

here; there's not much more that can be done without more information about your actual API (e.g., does the HANDLE is really a pointer trick work?). And even more reading at The simplest and neatest c++11 ScopeGuard, including a link 中列出了许多与提议的 std::unique_resource 类似的解决方案。