6

私は通常、pimplにboost :: scoped_ptrを使用します(コピーコンストラクターを処理するのを忘れても驚きがないため、1つの理由があります)

ただし、テンプレートでは、scoped_ptrのデストラクタの要件を満たすために、implが完全に定義されているcppファイルにデストラクタを配置することはできません。とにかく動作しますが、動作することが保証されているのか、それとも偶然なのかはわかりません。「ベストプラクティス」または標準はありますか?scoped_ptrは、コピー不可能なクラスのpimplsに最適なスマートポインターですか?

template <class T> class C {
public:
    C(){}
    ~C(){}
private:
    boost::scoped_ptr<T> pimpl_;
};
4

3 に答える 3

13

Herb Sutter が久しぶりに GotWs を書き始めたのはたまたまです。最初の新しいものの 1 つは、「コンパイル ファイアウォール」に関連しています。

以下をご覧ください。

GotW #100: コンパイル ファイアウォール (難易度: 6/10)

GotW #101: コンパイル ファイアウォール、パート 2 (難易度: 8/10)

于 2011-12-05T14:36:20.303 に答える
2

2 年後、スタック オーバーフローの回答を適切かつ最新の状態に保つために、状況をよりよく理解しています。

私の元の質問の前提には多少の欠陥があります。pimpl-idiom を使用する理由は、実装の詳細をコンパイラから隠すためです。これは、不透明なポインター (宣言されているが定義されていないデータ型へのポインター) を介して実装を格納することによって行われます。これにより、クラスと対話する他のコンパイル ユニットが必要とするヘッダーの量が大幅に削減され、コンパイル時間が短縮されます。私の質問のテンプレートの場合、インスタンス化の時点で型 T が完全に認識されている必要があります。実際には、impl の型がどこC<ImplType>で使用されても完全に定義されている必要があります。用語の古典的な意味。

プライベート ポインターを介してクラスのデータを保持する理由は他にもあります。たとえば、非スローの移動とスワップを簡単に実装でき、クラスが強力な例外保証を満たす必要がある場合にも適しています (copy and swap idiom を参照) 。コピー アンド スワップ イディオム? )。一方で、impl へのアクセスごとに間接レイヤー (多くの場合、キャッシュ ミスが発生します) が追加され、impl の作成および破棄時にヒープの割り当て/割り当て解除が行われます。これらはパフォーマンスにかなりのペナルティを与える可能性があるため、このソリューションを特効薬と見なすべきではありません。

C++11 を使用できる場合は、boost::scoped_ptr の代わりに std::unique_ptr を使用する必要があります。

于 2014-06-11T12:30:21.670 に答える
1

boost::shared_ptrインスタンス化の時点以外では、完全な定義は必要ありません。つまり、pimpl の場合はコンストラクターです。 ただし、非常に予期しないセマンティクス (代入またはコピーの参照セマンティクス) を提供するため、pimpl イディオムには適してboost::shared_ptrません。スマート ポインターの追加の複雑さが本当に必要な場合は、boost::scoped_ptrより適切です (ただし、デストラクタがインスタンス化される時点で完全な定義が必要です)。

テンプレートに関しては、ヘッダーの実装の詳細に pimpl イディオムを使用しても意味がありません。がexport存在しない場合、クラス テンプレートのすべての実装の詳細は、テンプレートが使用されるすべての場所に含まれている必要があるため、pimpl イディオムの背後にある動機は存在しなくなります。

于 2011-12-05T14:40:54.800 に答える