std :: unique_ptr的内存效率自定义删除器?

Kev*_*vin 8 c++ memory-management stl c++11

这可能有点特定于实现,但有些似乎是根本性的.

我确定我必须在标准库中遗漏一些东西.

问题是这样的:

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

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

当然,有很多选项可以做到这一点,但(至少在g ++ 4.8.4 for x86-64中)它们似乎有不同的内存使用含义.

例如:方法1:

std::unique_ptr<char, std::function<void(void*)>> ptr_a(malloc(10), free);
Run Code Online (Sandbox Code Playgroud)

但是, sizeof(ptr_a)== 40个字节(对于void*为8,对于std :: function <>为32)

方法2:

std::unique_ptr<void, void (*)(void*)> ptr_b(malloc(10), free);
Run Code Online (Sandbox Code Playgroud)

好一点,因为 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));`
Run Code Online (Sandbox Code Playgroud)

在这一点上,sizeof(ptr_c)== 8个字节(最小可能) - 但我必须引入一个非常纯粹的样板(并且如图所示,容易模板化)的类.

这看起来像是一个简单的模式 - STL中是否有一些元素能够Caller<>完成上述操作?

当然,默认情况下,当在一个普通类型上调用delete时,g ++确实看起来像free() - 但这似乎远不是标准所保证的(如果没有别的,可以从默认的分配/释放函数重新定义new/delete,并且然后default_delete将调用替换删除).

此外,在其他情况下,在纯C库中分配的某些对象的发布将通过简单的函数调用而不是删除器来实现.在类中包含这样的分配/释放函数似乎有点乏味,以便让std :: unique_ptr正确有效地调用它们 - 这让我觉得我缺少了一些东西(现代C++规范的其余部分)似乎非常深思熟虑).

Yak*_*ont 9

C++ 11有一种integral_constant类型可以处理非整数的东西.在C++ 14中,有一个constexpr强制转换为值.

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

std::unique_ptr<void, std::integral_constant<decltype(free)*, free>> ptr_c(malloc(10));
Run Code Online (Sandbox Code Playgroud)

这很尴尬.(这依赖于()将在其左侧参数上考虑强制转换功能指针的事实).

我们可以免费硬编码:

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

在使用现场摆脱一些噪音.

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

template<auto t>
using val = std::integral_constant< std::decay_t<decltype(t)>, t >;
Run Code Online (Sandbox Code Playgroud)

给我们:

std::unique_ptr<void, val<free>> ptr_c(malloc(10));
Run Code Online (Sandbox Code Playgroud)

在我看来这更干净.

实例.

我们可以在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));
Run Code Online (Sandbox Code Playgroud)

  • 哇,太酷了。我从来没有想过以这种方式使用`std::integral_constant`。 (2认同)

Hak*_*kes 0

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

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

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

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

  • 该对象变得很难在不违反编译单元之间的 ODR 的情况下传递。 (3认同)