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

时间:2017-07-27 04:22:07

标签: c++ c++11 memory-management stl

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

我确定我必须遗漏标准库中的内容。

问题在于:

我想实现一个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);

然而, sizeof(ptr_a) == 40个字节(8个用于void *,32个用于std :: function&lt;&gt;)

方法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将调用替换删除)。

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

2 个答案:

答案 0 :(得分:7)

C ++ 11有一个constexpr类型,适用于非整数类的东西。在C ++ 14中,有一个std::unique_ptr<void, std::integral_constant<decltype(free)*, free>> ptr_c(malloc(10)); 强制转换为值。

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

()

这很尴尬。 (这取决于using default_free = std::integral_constant<decltype(free)*, free>; std::unique_ptr<void, default_free> ptr_c(malloc(10)); 将在其左侧参数上考虑强制转换功能指针的事实。

我们可以免费硬编码:

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

在使用现场消除一些噪音。

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

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

给我们:

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));

在我看来更干净。

Live examples

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

Array
(
    [1] => Array
        (
            [a] => 18
            [f] => 0
            [f] => 0
            [l] => 61.60
        )
    [2] => Array
        (
            [a] => 38
            [f] => 0
            [f] => 0
            [l] => 11.99
        )
    [3] => Array
        (
            [a] => 28
            [f] => 0
            [f] => 0
            [l] => 3.40
        )
)

答案 1 :(得分:0)

还有第四种选择使用无状态lambda:

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