适用于 std::unique_ptr 的内存高效自定义删除器?

Memory-efficient custom deleter for std::unique_ptr?

本文关键字:自定义 高效 删除 内存 std unique ptr 适用于      更新时间:2023-10-16

这可能有点特定于实现,但其中一些似乎是基本的。

我确定我一定在标准库中缺少某些内容。

问题是这样的:

我想实现一个删除器为free()std::unique_ptr

[ 因为该值是通过malloc()分配的 ]

当然,有很多关于如何做到这一点的选择,但是 (至少在 x86-64 的 G++ 4.8.4 中(它们似乎具有不同的内存使用含义。

例如: 方法一:

std::unique_ptr<char, std::function<void(void*)>> ptr_a(malloc(10), free);

然而sizeof(ptr_a)== 40 字节(8 表示 void*,32 表示 std::function<>(

方法2:

std::unique_ptr<void, void (*)(void*)> ptr_b(malloc(10), free);

好一点,因为sizeof(ptr_b)== 16 个字节(8 个表示 void*,8 个表示裸函数指针 ](

方法3:

template <void (*T)(void*)>
class Caller {
public:
void operator()(void* arg) {
return T(arg);
}
};
std::unique_ptr<void, Caller<free>> ptr_c(malloc(10));`

在这一点上,sizeof(ptr_c)== 8 字节(可能的最小值( - 但我不得不引入一个几乎是纯样板的类(并且,如图所示,很容易模板化(。

这似乎是一个简单的模式 - STL 中是否有某些元素可以执行Caller<>上面所做的操作?

当然,当在一个普通类型上调用 delete 时,默认情况下 g++ 确实显示为 free(( - 但这似乎远非标准所保证的(如果没有别的,可以从默认的分配/释放函数重新定义 new/delete,然后default_delete调用替换 delete(。

此外,在其他情况下,在纯 C 库中分配的某些对象的释放将通过简单的函数调用而不是删除器来实现。 为了使 std::unique_ptr 正确有效地调用它们,必须将此类分配/释放函数包装在类中似乎有些乏味 - 这让我认为我错过了一些东西(大多数其余的现代C++规范似乎都经过深思熟虑(。

C++11 有一个integral_constant类型,适用于非整数类的东西。 在 C++14 中,有一个constexpr转换回该值。

因此,在 C++14 中,我们可以做到:

std::unique_ptr<void, std::integral_constant<decltype(free)*, free>> ptr_c(malloc(10));

这很尴尬。 (这依赖于这样一个事实,即()将在其左侧参数上考虑投射到函数指针(。

我们可以免费硬编码为:

using default_free = std::integral_constant<decltype(free)*, free>;
std::unique_ptr<void, default_free> ptr_c(malloc(10));

以消除使用现场的一些噪音。

在 C++17 中,我们可以编写一个助手:

template<auto t>
using val = std::integral_constant< std::decay_t<decltype(t)>, t >;

给我们:

std::unique_ptr<void, val<free>> ptr_c(malloc(10));

在我看来,这更干净。

活生生的例子。

我们可以在 C++11 中编写自己的版本:

template<class T, std::decay_t<T> t>
struct val {
constexpr operator T() noexcept const { return t; }
};
using default_free = val<decltype(free), free>;
std::unique_ptr<void, default_free> ptr_c(malloc(10));

还有使用无状态 lambda 的第 4 个选项:

auto free_lmbd = [](void *_ptr) { free (_ptr);};
std::unique_ptr<void, decltype (free_lmbd)> ptr {malloc(10), free_lmbd};

它也将有 8 个字节(至少在我的计算机上(,与您的第 3 个选项相同。

我建议阅读 http://www.bfilipek.com/2016/04/custom-deleters-for-c-smart-pointers.html