2017-07-27 15 views
4

これは実装固有のビットですが、その一部は基本的なようです。std :: unique_ptrのためのメモリ効率の良いカスタムディテクタ?

標準ライブラリで何かが欠けているはずです。

問題はこれです:

私は[値はmalloc()を経由して割り当てられるため]そのデリータfree()

あるstd::unique_ptrを実装したい

のオプションの多くは、もちろん、あります。これを行う方法は (少なくとも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、STD 32 ::機能<>)

方法2:

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

多少良くなって、 sizeof(ptr_b) == 16バイト(void *の場合8、裸の場合は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はデフォルトの割り当て/ deallocation関数を呼び出すと、default_deleteは置き換えdeleteを呼び出します)。

また、純粋なCライブラリに割り当てられたオブジェクトのリリースが、単純な関数呼び出しではなく、単純な関数で実装される場合もあります。このような割り当て/解放関数をクラスでラップして、std :: unique_ptrが正しくかつ効率的に呼び出されるようにするのは、ちょっと面倒なようです。何かが欠けていると思います(現代のC++仕様のほとんど非常によく考えられているように思われる)。あなたの第三の選択肢として

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

も(少なくとも私のコンピュータ上で)8つのバイトを持っていますが、同じ:

答えて

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

。私たちに与えて

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++ 17では、我々はヘルパーを書くことができます。

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 1つの欠点は、継承ベースのオーバーライドでは機能しないということです。 – Yakk

関連する問題