如何仅对删除器使用 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
类似的解决方案。
我只是想使用 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
类似的解决方案。