54

pimplイディオムを使用していくつかのオブジェクトを作成してきましたが、を使用するか、を使用するかがわかりませstd::shared_ptrstd::unique_ptr

私はそれがより効率的であることを理解していますが、これらのオブジェクトはとにかく比較的重いので、オーバーstd::unique_ptrのコストは比較的小さいので、これは私にとってそれほど問題ではありません。std::shared_ptrstd::unique_ptr

私は現在std::shared_ptr、柔軟性が高いという理由だけで取り組んでいます。たとえば、を使用するとstd::shared_ptr、これらのオブジェクトのコピーを呼び出し元に返すことができる一方で、これらのオブジェクトをハッシュマップに格納してすばやくアクセスできます(イテレータまたは参照はすぐに無効になる可能性があるため)。

ただし、変更はすべてのコピーに影響するため、これらのオブジェクトは実際にはコピーされていません。したがって、std::shared_ptrコピーの使用と許可は、ある種のアンチパターンまたは悪いことであるのではないかと思いました。

これは正しいです?

4

4 に答える 4

38

pimpl イディオムを使用していくつかのオブジェクトを作成してきましたが、または を使用するかどうかはわかりませshared_ptrunique_ptr

間違いなくunique_ptrまたはscoped_ptr

Pimplはパターンではなく、コンパイル時の依存関係とバイナリ互換性を扱うイディオムです。特にコピー動作に関して、オブジェクトのセマンティクスに影響を与えるべきではありません。

内部ではどんな種類のスマート ポインターでも使用できますが、コピー コンストラクターと代入演算子の実装について意識的な決定が必要になるため、2 つの異なるオブジェクト間で誤って実装を共有しないことが保証されます。

ただし、変更はすべてのコピーに影響するため、これらのオブジェクトはある意味で実際にはコピーされていません。したがって、コピーを使用shared_ptrして許可することは、ある種のアンチパターンまたは悪いことではないかと考えていました。

これはアンチパターンではなく、実際にはパターン、つまりエイリアシングです。C++ では、そのままのポインターと参照を使用して既に使用しています。shared_ptr追加の複雑さと新しい問題を犠牲にして、デッドリファレンスを回避するための追加の「安全性」を提供します (メモリリークを引き起こすサイクルに注意してください)。


にきびとは無関係

より効率的であることは理解していますが、これらのオブジェクトはとにかく比較的重いため、オーバーunique_ptrのコストは比較的小さいため、これは私にとってそれほど問題ではありません。shared_ptrunique_ptr

いくつかの状態を因数分解できる場合は、Flyweightパターンを調べてみてください。

于 2011-04-07T07:11:25.327 に答える
12

を使用する場合shared_ptr、それは実際には古典的な pimpl イディオムではありません (追加の手順を実行しない限り)。しかし、本当の問題は、そもそもなぜスマート ポインターを使いたいのかということです。どこで発生するかは非常に明確であり、delete例外の安全性やその他の懸念事項はありません。せいぜい、スマート ポインターを使用すると、1 ~ 2 行のコードを節約できます。そして、正しいセマンティクスを持つ唯一のものはboost::scoped_ptrであり、この場合は機能しないと思います。(IIRC、インスタンス化するには完全な型が必要ですが、間違っている可能性があります。)

pimpl イディオムの重要な側面は、その使用がクライアントに対して透過的であることです。クラスは、従来の方法で実装されているかのように動作する必要があります。これは、クラスが不変 (非 const メンバー関数がない) でない限り、コピーと割り当てを禁止するか、ディープ コピーを実装することを意味します。通常のスマート ポインターはディープ コピーを実装していません。もちろん、実装することもできますが、コピーが発生するたびに完全な型が必要になる可能性があります。つまり、ユーザー定義のコピー コンストラクターと代入演算子を提供する必要があります (インラインにすることはできないため)。これを考えると、わざわざスマート ポインターを使用する価値はないでしょう。

例外は、オブジェクトが不変の場合です。この場合、コピーが深いかどうかは関係なく、shared_ptr 状況を完全に処理します。

于 2011-04-07T08:23:28.593 に答える
6

shared_ptr(たとえば、コンテナ内で、これを検索してで返す)を使用する場合、それが指すオブジェクトのコピーを作成するのではなく、参照カウントを含むポインタのコピーを作成するだけです。

つまり、基になるオブジェクトを複数のポイントから変更すると、同じインスタンスの変更に影響します。これはまさにそれが設計されているものなので、アンチパターンではありません!

(コメントが言うように) aを渡すときshared_ptrは、const参照を渡し、必要に応じて(参照カウントをインクリメントして)コピーすることをお勧めします。返品については、ケースバイケースです。

于 2011-04-07T06:39:52.657 に答える