2012-03-14 15 views
45

私は既存のコードを "近代化"しようとしています。関数にunique_ptrを渡す

  • 現在、メンバー変数 "Device * device_"を持つクラスがあります。
  • これは、いくつかの初期化コードでインスタンスを作成するためにnewを使用し、destructoryに「delete device_」を持っています。
  • このクラスのメンバ関数は、manyを呼び出す他の関数をパラメータとして使用します。

これはうまく動作しますが、私のコードを「近代化」に私は"std::unique_ptr<Device> device_"のように定義する変数を変更し、コードをより安全かつ一般的に良くなり、削除する明示的な呼び出しを削除するべきであると思いました。どのように私は、その後のparamaterとしてそれを必要とするすべての機能にデバイス _変数を渡す必要があり

  • -

    私の質問はこれですか?

各関数呼び出しで生のポインタを取得するために.getを呼び出すことができます。しかし、これは醜いと思われ、最初にunique_ptrを使用する理由のいくつかを無駄にします。

または「*デバイス」、それは今のタイプののparamater取る代わりに、型のパラメータを取るように「のstd :: unique_ptrをを&」私はごと機能を変更することができます。これは(私にとって)関数プロトタイプをやや難解にし、読みにくいものにします。

これにはどのようなベストプラクティスがありますか?他の選択肢がありませんでしたか?

+3

を渡しますか?あなたの説明から、私は正反対が真実だと言います。 –

+0

@James Kanze私は同意します、unique_ptrはこの場合何も買わないようです。 – juanchopanza

+2

あなたは正しいかもしれません。私はあなたがそれを削除することを忘れてはいけないという点でunique_ptrの "安全"が好きですが、この場合はいくらかのコストがかかるようです。 – jcoder

答えて

44

現代 C++スタイルでは、二つの鍵の概念がある:

  • NULLかどうか

    • 所有

    所有、この場合には(いくつかのオブジェクト/リソースの所有者についてです、Deviceのインスタンス)。さまざまなstd::unique_ptr,boost::scoped_ptrまたはstd::shared_ptrは所有権に関するものです。

    Nullityは、特定のオブジェクトがnullである可能性があり、何も気にしないで、オーナーシップではないことを表しています。


    あなたは正しいあなたの目標はPIMPLを実装することであるならば、あなたは深いコピー・セマンティクスを持つスマートポインタをしたいかもしれませんが、(一般的に)unique_ptrに向かって自分のクラスの実装を移動するにはました。

    これは、あなたのクラスがこのメモリを担当する唯一のクラスであることを明確に伝え、メモリが漏れていた可能性のあるさまざまな方法すべてをきちんと扱います。一方


    、最もユーザーリソースのは、その所有権についてはあまり気にしませんでした。

    関数がオブジェクトへの参照を保持していない限り(マップまたは何かに格納する)限り、オブジェクトの存続期間は関数呼び出しの持続時間を超えていることが重要です。

    このように、パラメータを渡す方法を選択すると、その可能NULLかどうかに依存します:

    • ヌル決して?合格参照
    • おそらくnull?なぜ、この変更は、コードをより安全かつ一般的に良くなるだろうポインタ、(例えばヌルのトラップで)簡単な裸のポインタまたはポインタのようなクラス

  • +0

    うーん、参考... 私の関数は "デバイスとデバイス"のパラメータを取ることができますし、呼び出し元のコードで* device_を使用してもunique_ptrと同様に動作し、device_はnullにはならないことがわかります(アサートでもテストできます)。今私はちょっと熟考して、それが醜いかエレガントかどうかを判断する必要があります! – jcoder

    +2

    @ JohnB:私のbiaisedの視点は、コンパイル時の無限の可能性をなくすことです。 –

    +6

    @JohnB:Matthieuと完全に同意します。ポインタを保持しているオブジェクトの存続期間によってバインドされたオブジェクトを割り当てますか?なぜそれを自動記憶装置を備えたプレーンなメンバーとして宣言しないのですか? –

    7

    私はstd::unique_ptr const&を使用します。非const参照を使用すると、呼び出された関数にポインタをリセットする可能性が与えられます。
    これは、あなたの呼び出された関数がポインタを使うことができるが、それ以外は何も表現できないことを表現する良い方法だと思います。
    私にとっては、これによりインターフェイスが読みやすくなります。私はポインタが私に渡されて周りを回る必要はないことを知っています。

    +0

    したがって、constを追加すると、私はunique_ptrを変更することはできませんが、unique_ptr経由で含まれているオブジェクトの非const関数を呼び出せますか? – jcoder

    +0

    @ JohnB:はい、constは、呼び出された関数があなたのunique_ptrを呼び出してリセットするのを防ぎます。しかし、ポインタがconstでない限り、非const関数を呼び出すことができます。 – mkaes

    +0

    はいできます。 unique_ptrのget()constメソッドは、unique_ptrによって保護されているオブジェクトへの非constポインタを返します。 – zabulus

    1

    これは実現可能ではないかもしれませんが、すべての出現をDevice*で置き換えることによって、const unique_ptr<Device>&が良いスタートです。

    あなたは明らかにunique_ptrをコピーすることはできません。あなたはそれを移動したくありません。 unique_ptrへの参照で置き換えることで、既存の関数の本体の本体が動作し続けることができます。

    トラップがあるので、unique_ptr.reset()またはunique_ptr().release()の呼び出しを防ぐには、const &を渡す必要があります。これはまだ変更可能なポインタをデバイスに渡すことに注意してください。このソリューションでは、ポインタまたは参照をconst Deviceに渡す簡単な方法はありません。

    +0

    const unique_ptr &が扱いにくいので、Device_tまたはそれに類するものをtypedefします。 –

    14

    本当に依存しています。関数がunique_ptrの所有権を取らなければならない場合、その署名はunique_ptr<Device> bv の値をとり、呼び出し元はポインタstd::moveでなければなりません。所有権が問題でなければ、生ポインタの署名を保持し、ポインタunique_ptrをget()を使って渡します。これは醜いものではありません問題の機能が所有権を引き継ぎません。

    +0

    はい私は所有権を奪うつもりはなく、関数の中でオブジェクトを指し示すだけです。 – jcoder

    +2

    所有権が問題でない場合は、unique_ptrにconst参照を渡すこともできます。 Pascalsのin-out形式パラメータのセマンティクス(Google C++スタイルガイド)をシミュレートするためにポインタ参照二分法を使用する人もいます。 –

    2

    std::unique_ptrこのケースでは、おそらく は使用しないことをお勧めします。 (通常、クラス内の動的に割り当てられたオブジェクトへのポインタは、 という生のポインタを1つだけ持つべきではありませんが、この も依存しますが) はstd::unique_ptrあなたは気付いた、 std::unique_ptr<> const&は少し扱いに​​くく、難読化している)です。この がオブジェクト内の唯一の動的に割り当てられたポインタである場合、私は生ポインタで とデストラクタにdeleteを貼り付けます。 このようなポインタがいくつかある場合は、それぞれを 別の基底クラス(それらはまだ未加工のポインタ)に降格することを検討したいと思います。