2016-05-08 5 views
3

に、私はクラスFooを持っていると仮定する:の割り当ては、*これはコンストラクタ

class Foo { 
public: 
    Foo(std::string s) noexcept : bar(std::move(s)) {} 

    // version 1 
    Foo(int x) noexcept 
    { 
     // do something... 
     std::string s = // ...to get a string from `x` 
     *this = Foo(std::move(s)); 
    } 

    // version 2 
    Foo(int x) noexcept 
     : Foo([x] { 
      // do something... 
      std::string s = // ...to get a string from `x` 
      return Foo(std::move(s)); 
     }()) 
    {} 

private: 
    std::string bar; 
}; 

バージョン1は、クリーンなコードを持っていますが、2つの欠点があります:1)メンバーのデフォルトの初期化は高価である場合、またはconstが存在する場合メンバーは、このバージョンは動作しません。 2)はコンストラクタ内で*thisに割り当てられていますか?コンストラクタが返される前に、オブジェクトが「不完全な」状態になっている可能性があるため、この質問があります。

+1

あなたはC++ 11を持っていますので、委任コンストラクタを使用してみませんか? 'Foo(int x):Foo(std :: to_string(x)){}' – kfsone

+0

@kfsoneバージョン2のアイデアはそれだけです。この場合、文字列を直接返すことができましたが、実際のコードでは委譲されたコンストラクタに複数の引数が渡されるため、代わりに移動コンストラクタに委譲する必要があります。 –

答えて

3

はい、あなたはそれを行うことができます。コンストラクタ本体の実行が開始されるまでに、すべてのフィールドが初期化され、オブジェクトが割り当てられるのに有効です。 (代入演算子がコンストラクタ本体の後半で確立された前提条件に依存していないと仮定します)。

2

はそれをシンプルに保つ:

Foo(int x) noexcept : Foo(getString(x)) { } 

private: 
    std::string getString(int x) { // make it static if possible 
     // do something... 
     return // ...get a string from `x` 
    } 
+1

は委譲されたコンストラクタを呼び出す前にインスタンスメソッドを安全に呼び出していますか? –

+2

'getString'を' static'にしたいと思います。可能であれば、yesを入力してください。 – 5gon12eder

+0

@ 5gon12eder – emlai

1

*this = Foo(std::move(s));を意味し、コンストラクタから関数を呼び出すことができます。

私が見る唯一の問題は、この文字列のすべてがプログラムを終了させるメモリ不足例外をスローする可能性があることです。おそらく、クラスが将来複雑になるように開発されれば、問題が発生する可能性があると考えるかもしれませんが。

このコードでは、barを空の文字列に初期化して文字列を割り当てるという小さな問題があります。あなたがbarの値を返す関数calculate_stringを書くことができますが、文字列が保持する値、例えば:

Foo(int x) noexcept: bar(calculate_string(x)) {} 

barを初期化する方が良いだろう。

関連する問題