5

代入演算子が void を返すことができるのはなぜですか? そして、この場合、割り当てチェーンが機能するのはなぜですか? コードを見てください。私が何について話しているのかは非常に明確です。

コード:

struct Foo
{
   std::string str;

   Foo(const std::string& _str)
   : str(_str)
   {
   }

   Foo& operator=(const Foo& _foo)
   {    
      str = _foo.str;
      //return *this; /* NO RETURN! */
   }
};

int main()
{
   Foo f1("1");
   Foo f2("2");
   Foo f3("3");
   f1 = f2 = f3 = Foo("4");

   std::cout << "f1: " << f1.str << std::endl;
   std::cout << "f2: " << f2.str << std::endl;
   std::cout << "f3: " << f3.str << std::endl;

   return 0;
}

質問:

  1. なぜこれが合法なのですか?(なぜそれはまったくコンパイルされますか)
  2. なぜそれが機能するのですか?

私は多くの場所で「代入演算子は * thisを返す必要があるため、代入チェーンを使用できるようにする必要があります」と読んだことがありますが、これは完全に理にかなっていますが、なぜ上記が機能するのですか?

試してみてください:
上記のコードを使用したオンライン C++ ワークスペース

4

4 に答える 4

8

なぜこれが合法なのですか?(なぜコンパイルするのですか)

これは合法ではなく、プログラムに未定義動作を注入します。あなたのコンパイラは少なくともそれについてあなたに警告するべきです(そしてあなたが十分に高い警告レベルを設定すれば、私はそれがそうすると信じています)。

C++11規格の6.6.3/2項によると:

関数の終わりから流れ出るのは、値のない戻りと同じです。これにより、値を返す関数で未定義の動作が発生します

唯一の例外は関数です。この関数では、ステートメントmain()が欠落している可能性があります。return3.6.1 / 5項による:

のreturnステートメントにmainは、main関数を終了し(自動保存期間のあるオブジェクトを破棄し)std::exit、引数として戻り値を使用して呼び出す効果があります。制御がreturnステートメントに遭遇せずに最後に到達した場合main、その効果は実行の効果です。

return 0;

ついに:

なぜそれが機能するのですか?

未定義動作とは、プログラムが一部のマシンで実行される可能性があるが、他のマシンでは実行されない可能性があることを意味します。または、今日はすべてのマシンで実行できますが、明日は実行できません。または、プログラムに奇妙で予測できない結果が生じる可能性があります。(これは最悪の場合ですが)完全に正常に動作しているように見えます。

于 2013-03-18T10:27:58.577 に答える
2

何かを返すことを約束する関数の終わりから流れ出ているので、あなたが持っているのは未定義の振る舞いです。

C ++でこれを行うことが合法である唯一の関数は(そして引数付きのバージョン)です。これは、returnステートメントがない場合にint main()暗黙的に戻るためです。0

于 2013-03-18T10:28:24.847 に答える
0

それは違法であり、コンパイルされた場合、何らかの方法でランタイムに奇妙なものを保存しています。そして、関数から戻る必要があり*thisます。正しい関数定義は次のようになります。

Foo& operator=(const Foo& _foo)
{    
  if(this == &_foo) /* check for self-assignment */
     return *this;

  str = _foo.str;

  return *this;
}

*this次のようなチェーン割り当てでは、返品が必須です。

Foo  x, y, z;
x = y = z;     /* *this is necessary for this statement */    
于 2013-03-18T10:40:37.980 に答える
0

コンパイル後に生成される asm コードを確認します。私の推測では、この関数は、たまたまレジスタ AX にあるものを返すということです (私が間違っていなければ、これは c-call 標準関数の実装です)。あなたの場合、それはたまたまあなたが望んでいるものです...機能する機能を追加すると、それが壊れる可能性があります...

于 2013-03-18T10:37:22.917 に答える