这可能有点特定于实现,但其中一些似乎是基础性的。
我确定我一定在标准库中遗漏了一些东西。
问题是这样的:
我想实现一个 std::unique_ptr
删除器是free()
[因为值是通过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<>)
方法二:
std::unique_ptr<void, void (*)(void*)> ptr_b(malloc(10), free);
稍微好一点,因为
sizeof(ptr_b)
== 16 个字节(8 个用于 void*,8 个用于裸函数指针])
方法三:
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<>
的操作?以上呢?
当然,默认情况下 g++ 确实在对普通类型调用 delete 时出现 free() - 但这似乎远未得到标准的保证(如果不出意外,可以从默认分配/取消分配重新定义 new/delete函数,然后 default_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));
关于c++ - std::unique_ptr 的高效内存自定义删除器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45341371/