gpt4 book ai didi

c++ - typedef 具有静态自定义删除器的 shared_ptr 类型,类似于 unique_ptr

转载 作者:太空狗 更新时间:2023-10-29 20:12:30 28 4
gpt4 key购买 nike

我已经阅读了很多关于 shared_ptrunique_ptr 的自定义删除器的问题,以及两者之间的区别。但是,我仍然没有找到这个问题的明确答案:

如何才能最好地创建一个类型,该类型充当具有自定义删除器的 shared_ptr,类似于 unique_ptr 如何将删除器作为类型定义的一部分?

对于 unique_ptr 用法,我使用了一个删除器类,它处理单个类型的删除(为简洁起见,将其限制为只有两种类型):

struct SDL_Deleter {                                
void operator()( SDL_Surface* ptr ) { if (ptr) SDL_FreeSurface( ptr );}
void operator()( SDL_RWops* ptr ) { if (ptr) SDL_RWclose( ptr );}
};

using SurfacePtr = std::unique_ptr<SDL_Surface, SDL_Deleter>;
using RWopsPtr = std::unique_ptr<SDL_RWops, SDL_Deleter>;

可以和类似的东西一起使用

SurfacePtr surface(IMG_Load("image.png"));

并且会在销毁时调用 SDL_FreeSurface


这一切都很好。但是,如何为 shared_ptr 实现相同的目标?它的类型定义为

template< class T > class shared_ptr;

提供自定义删除器的方法是通过构造函数。 shared_ptr 包装器的用户需要知道包装了哪种指针类型,以及应该如何删除该指针,这感觉不对。实现与上述 unique_ptr 示例相同类型用法的最佳方法是什么。

换句话说,我可能会得到:

SurfaceShPtr surface(IMG_Load("image.png"));

而不是类似的东西

SurfaceShPtr surface(IMG_Load("image.png"),
[=](SDL_Surface* ptr){SDL_FreeSurface(ptr);});

或者,稍微好一点

SurfaceShPtr surface(IMG_Load("image.png"),
SDL_Deleter());

有没有办法做到这一点,而不必创建 RAII 包装类(而不是 typedef),增加更多的开销?


如果答案是“这不可能”。为什么不呢?

最佳答案

这里提供的另一个答案是,可以通过带有自定义删除器的 unique_ptr 函数返回来完成一些接近我所要求的事情,它可以隐式转换为 shared_ptr .

给出的答案是定义为类型特征的删除器对于 std::shared_ptr 是不可能的。建议的答案作为替代方案,使用返回 unique_ptr 的函数,隐式转换为 shared_ptr

因为这不是类型的一部分,所以可能会犯一个简单的错误,导致内存泄漏。这是我想避免的。

例如:

// Correct usage:
shared_ptr<SDL_Surface> s(createSurface(IMG_Load("image.png")));

// Memory Leak:
shared_ptr<SDL_Surface> s(IMG_Load("image.png"));

我想表达的概念是将删除器作为类型的一部分(unique_ptr 允许),但具有 shared_ptr 的功能。我建议的解决方案是派生自 shared_ptr,并提供删除器类型作为模板参数。这不会占用额外的内存,并且与 unique_ptr 的工作方式相同。

template<class T, class D = std::default_delete<T>>
struct shared_ptr_with_deleter : public std::shared_ptr<T>
{
explicit shared_ptr_with_deleter(T* t = nullptr)
: std::shared_ptr<T>(t, D()) {}

// Reset function, as it also needs to properly set the deleter.
void reset(T* t = nullptr) { std::shared_ptr<T>::reset(t, D()); }
};

连同删除器类(感谢 Jonathan Wakely。比我的宏(现已删除)干净得多):

struct SDL_Deleter
{
void operator()(SDL_Surface* p) const { if (p) SDL_FreeSurface(p); }
void operator()(SDL_RWops* p) const { if (p) SDL_RWclose(p); }
};

using SurfacePtr = std::unique_ptr<SDL_Surface, SDL_Deleter>;
using SurfaceShPtr = shared_ptr_with_deleter<SDL_Surface, SDL_Deleter>;

using RWopsPtr = std::unique_ptr<SDL_RWops, SDL_Deleter>;
using RWopsShPtr = shared_ptr_with_deleter<SDL_RWops, SDL_Deleter>;

具有 SurfaceShPtr 成员的实例类型保证正确清理,与 SurfacePtr 相同,这正是我想要的。

// Correct Usage (much harder to use incorrectly now):
SurfaceShPtr s(IMG_Load("image.png"));

// Still correct usage
s.reset(IMG_Load("other.png"));

我会暂时搁置此问题,以征求意见等,但不接受答案。也许我错过了更危险的警告(非虚拟析构函数不是一个,因为父 shared_ptr 负责删除)。

关于c++ - typedef 具有静态自定义删除器的 shared_ptr 类型,类似于 unique_ptr,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27331315/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com