2017-07-27 78 views
4

這可能有點特定於實現,但其中一些似乎很重要。用於std :: unique_ptr的內存高效定製刪除程序?

我確定我必須在標準庫中丟失一些東西。

問題是這樣的:

我想實現一個std::unique_ptr其刪除器free()

[因爲該值是通過malloc()分配]有,當然,很多的選擇上如何做到這一點,但 (至少在g ++ 4.8.4 x86-64),他們似乎有不同的內存使用含義。

例如: 方法1:

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

然而, sizeof(ptr_a) == 40個字節(8個用於無效*,32爲標準::功能<>)

方法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<>上面做的?

當然,默認情況下g ++在調用一個普通類型的delete時確實顯示爲free(),但這似乎遠沒有標準保證(如果沒有其他的話,new/delete可以從默認分配/解除分配函數,然後default_delete將調用替換刪除)。

而且,還有其他一些情況,其中在純C庫中分配的某些對象的發佈將通過簡單的函數調用而不是刪除器來實現。爲了讓std :: unique_ptr能夠正確和高效地調用它們,這必須在類中包裝這樣的分配/釋放函數似乎有點乏味 - 這讓我覺得我錯過了一些東西(大部分現代C++規範的其餘部分似乎是非常深思熟慮)。

回答

0

還存在使用無狀態拉姆達第四選項:

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

這也將有8個字節(至少在我的電腦上),與您的第三個選項。

我建議你閱讀http://www.bfilipek.com/2016/04/custom-deleters-for-c-smart-pointers.html

+1

這個對象變得難以通過周圍沒有編譯單元之間違反ODR。 – Yakk

+0

是的,你是對的。 – Hakes

4

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

這在我看來是清潔的。

Live examples

我們可以寫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)); 
+0

哇,很酷。我從來沒有想過這樣使用'std :: integral_constant'。 – Quentin

+0

@Quentin其中一個缺點是它不適用於基於繼承的覆蓋。 – Yakk