2016-01-08 23 views
5

私はちょうどstd::shared_ptrの「エイリアシングコンストラクタ」を発見し、自分がなぜ::対応するものを持ってunique_ptrをはstdいない」尋ねる見つけました?なぜstd :: unique_ptrにstd :: shared_ptrのようなエイリアシングコンストラクタがないのですか?

あなたはFooあなたができるように割り当てたい場合、すなわちそうすることができるように素敵ではないでしょう、完全にFooの寿命を管理する必要がある関数にそのBarメンバーを渡すか?これは、STDと連携

#include <memory> 

struct B {} 
struct A { 
    B b; 
} 

void f(std::unique_ptr<B> b); 

std::unique_ptr<A> a = std::make_unique<A>(); 
std::unique_ptr<B> b { std::move(a), &(a->b) }; // a now invalid. 
f(std::move(b)); // f now responsible for deleting the A. 

を:: shared_ptrの(http://ideone.com/pDK1bc

#include <iostream> 
#include <memory> 
#include <string> 

struct B { 
    std::string s; 
}; 
struct A { 
    B b; 
    A(std::string s) : b{s} {}; 
    ~A() { std::cout << "A deleted." << std::endl; } 
}; 

void f(std::shared_ptr<B> b) { 
    std::cout << "in f, b->s = " << b->s << " (use_count=" << b.use_count() << ")" << std::endl; 
} 

int main() { 
    std::shared_ptr<A> a = std::make_shared<A>("hello"); 
    std::shared_ptr<B> b { a, &(a->b) }; 
    a.reset(); // a now invalid. 
    std::cout << "before f, b->s = " << b->s << " (use_count=" << b.use_count() << ")" << std::endl; 
    f(std::move(b)); // f now responsible for deleting the A. 
    std::cout << "after f" << std::endl; 
    return 0; 
} 

は期待

before f, b->s = hello (use_count=1) 
in f, b->s = hello (use_count=1) 
A deleted. 
after f 

はそのような事が含まれていなかった理由を論理的な理由がある出力しますか?そして/または、Aを削除するカスタムディターターを使用してunique_ptr<B>でエミュレートするのは悪い考えですか?

答えて

8

「問題」はstd::shared_ptrとは異なり、std::unique_ptrの削除者はタイプ消去されていないと思います。 std::unique_ptr<T>の既定の削除者(サイズがゼロで、型自体にほとんど見えない既定の型パラメーターとしてエンコードされます)は、単に[](T * p){ delete p; }です。しかし、std::make_unique<B>によって作成されたstd::unique_ptr<B>と、AオブジェクトのBメンバを指すことによって作成されたものは、同じDeleterを持つことができないことは明らかです。後者の場合の削除者は、元のA *ポインタバックを取得するためにポインタ演算を行う必要があります。これらの2つの削除者は、元のオブジェクトへのオフセットまたは内部ポインタを両方とも格納する場合にのみ、同じ型を持つことができます。そして、それはもはやゼロサイズを持たないでしょう。 std::unique_ptrは、手動でnewdeleteを実行するのに比べ、オーバーヘッドがゼロになるように設計されています。これは良いことです。私は、この便利なポインタを見つけなければならないユースケースを見つけなければならないが、その追加ポインターを格納している自分のレポーターを使用することで直ちに欠点を見ることはできない。

5

shared_ptrには参照カウントオーバーヘッドがあります。参照カウントブロックには、明示的なディレターも格納されています(ヒープに格納する場合は何バイトですか)。

これは基本タイプのshared_ptrが、仮想のdtor。

unique_ptrは、インスタンスにそのdeleterを格納します。デフォルトのdeleterは、ステートレスです(0バイトが使用されます)。これにより、unique_ptrは、メモリ使用量に関して生ポインタに対してオーバーヘッドがゼロになります。

ステートレスデリターは、他のものを削除することを忘れることはできません。

エイリアスをサポートするステートフルデリターをunique_ptrに追加できますが、手動で別名を付ける必要があります。コンストラクタの1つは、ポインタとデリータの両方をとります。

+0

そして、Deleterの型の部分以来、Deleterを消去しない限り、それは普通のunique_ptr とはうまく組み合わされません。それはさらに余分なオーバーヘッドです。 –

+0

@ T.C:Deleterをタイプしても、それは 'unique_ptr >'とうまく相互作用しません。少なくとも、一方向のみの変換が可能です。 –

+0

@ben理論上両方の方法で、失敗が許される限り。 – Yakk

関連する問題