2017-11-14 3 views
0

私は、次のクラス定義を持っている:C++ unique_ptrを関数に渡しても、多形性の恩恵を受けるにはどうすればよいですか?

class A {...} 
class B : public class A {...} 

と所有者のクラス定義:

class C { 
    A* a; 
public: 
    C (A* a) { this->a = a; } 
} 

私は次のように呼び出すしようとするとその後、すべてが正常である:

B* b = new B(); 
C(b); 

しかし、私は次のオーナークラス定義を持っています:

class C { 
    std::unique_ptr<A> a; 
public: 
    C(std::unique_ptr<A>& a) { this->a = std::move(a); } 
} 

そして、私は次のように呼び出すしようとすると、私はの&をunique_ptrをするためにBのunique_ptrをから変換することはできませんと言って、コンパイラのエラーを取得:

std::unique_ptr<B> b(new B()); 
C(b); 

私はそのSTDを実現行い:: &とstd unique_ptrを:: unique_ptrは同じではありません。しかし、私は、標準プロトコルが所有するクラスに一意のポインタを渡すためのものであるかどうかはわかりません。

私は次のことを試してみました:

class C { 
    std::unique_ptr<A> a; 
public: 
    C(std::unique_ptr<A> a) { this->a = std::move(a); } 
} 

std::unique_ptr<B> b = std::make_unique<B>(); 
C(std::move(b)); 

代わりのshared_ptrのunique_ptrを使用しての目的の一部ではないから、その性能向上を得ることですので、これは、動作しますが、カウンター直感的に感じていますメモリアドレスをコピーする必要があります。しかし、この場合、メモリアドレスをコピーするのではなく、新しいunique_ptrを作成して値渡しするだけで、関数が有効範​​囲外になったらそれを投げることができます。

注:私は変更可能な参照によって独特のポインタを渡さないVS C++コンパイラ11

+0

func関数には、次のように指定します。a unique_ptr:func(a.get()); – sailfish009

+0

ドキュメント(http://en.cppreference.com/w/cpp/memory/unique_ptr/make_unique)によると、 'std :: make_unique'はC++ 14です(したがって、既にC++ 14 **機能を使用しています)。そうでなければ、私はC++ 11と14の間で 'std :: unique_ptr'に大きな変化はないと思います。あなたの' C'コンストラクタはおそらく 'C(std :: unique_ptr && a)です:a(std :: move(a)){} 'を実行します。 – Phil1970

+2

@ sailfish009クラスCはポインターの所有権を取って答えがうまくいかないようにする必要があります。 – jahithber

答えて

1

を使用しています。このようなバグがあります。

実際にソリューションを値渡しすることです:

class C { 
    std::unique_ptr<A> a; 
public: 
    C(std::unique_ptr<A> a) { this->a = std::move(a); } 
} 

// ... 

auto b = std::make_unique<B>(); 
C(std::move(b)); 

代わりのshared_ptrのunique_ptrを使用しての目的の一部をする必要がないから、その性能向上を得ることですので、これは、動作しますが、カウンター直感的に感じていますコピーメモリアドレス。

いいえユニークなptrの利点は、ユニークな所有権を持つポインタよりもオーバーヘッドの抽象度が低いことです。

共有ポインタにはコストがかかります。それらがコピーされるたびに、原子の参照カウントが実行されます。これはキャッシュを傷つけ、無視できるオーバーヘッドではありません。また、共有ポインタは誰を所有しているのかを隠す。所有者の数は実行時に決定されるため、コードを考えるのが難しくなります。

ちなみに、アドレスのコピーにはほとんどオーバーヘッドがありません。参照は、ポインタの用語で実装されたほとんどの時間です。生ポインタのコピーは、参照渡しと同じコストです。 std::unique_ptrはゼロのオーバーヘッド抽象化であるため、一意のポインタをコピー(または移動)することは、生ポインタをコピーするのと同じコストとなり、参照渡しとほぼ同じコストになります。ポインタのコピーのパフォーマンスを心配する必要はありません。

しかし、その代わりに、メモリアドレスをコピーするので、この場合には、関数がスコープ外になった後にのみ、それを離れて投げるために、値だけで、それを渡すために、ブランドの新しいunique_ptrを作成です。

新しいunique_ptrを作成することは、メモリアドレスをコピーするのと同じコストです。他の一般的な言語とは異なり、C++オブジェクトはデフォルトでスタックに格納されており、ネイティブ型を扱うのと同じパフォーマンスを提供します。


パフォーマンスが心配な場合は、最適化してコンパイルし、コードとベンチマークをプロファイルします。あなたがそれを測定しない限り、パフォーマンスに関する声明は無意味です。コンパイラのアセンブリ出力を調べた場合、それらはexactly the sameであることがわかります。

免責事項:それもO2に離れて全体のコードを省略さので、私は、実際の例で打ち鳴らすを使用してコンパイルされませんでした。

+0

答えていただきありがとうございます。代わりにrvalue-referenceを渡すとどう思いますか?それは価値の代わりにより効率的でしょうか?それがあれば、避けるべき落とし穴はありますか? – jahithber

+0

rvalue参照を渡す@ jahithberは、再び、新しい値を作成するのと同じです。自分でお試しください!コンパイラがあなたのコードで何をするかを見ることができるすばらしいウェブサイトをリンクしました。しかし、落とし穴があります:参照渡しは所有権を譲渡しません。左辺値参照で転送するには移動を使用する必要がありますが、右辺値を受け取る関数は実際に値を移動するかどうかに関わらず、値が実際に移動されない可能性があります。私はrvalue参照でunique_ptrを渡すことを決して勧めません。 –

+0

@jahithberまた、最適なコードを実際に作成したい場合は、ベンチマークを作成しプロファイルします。パフォーマンスについての他の議論は、あなたがそれを疑っていない限り、推測です。私があなたに示したウェブサイトは、パフォーマンスが同じであることを証明しました。アセンブリの出力が異なり、パフォーマンスが心配な場合は、*あなたのコードをプロファイルします*。 –

関連する問題