77

このコードを考えてみましょう:

struct foo
{
  int a;
};

foo q() { foo f; f.a =4; return f;}

int main()
{
  foo i;
  i.a = 5;
  q() = i;
}

Clangでさえ、コンパイラはそれについて文句を言いません。なぜq() = ...線が正しいのですか?

4

4 に答える 4

70

いいえ、関数の戻り値は、それが参照(C ++ 03)である場合に限り、l値です。(5.2.2 [expr.call] / 10)

返される型が基本型である場合、これはコンパイルエラーになります。(5.17 [expr.ass] / 1)

これが機能する理由はconst、クラスタイプのr値でメンバー関数(非メンバー関数であっても)を呼び出すことが許可されており、の割り当てがfoo実装定義のメンバー関数であるためですfoo& foo::operator=(const foo&)。条項5の演算子の制限は、組み込み演算子(5 [expr] / 3)にのみ適用されます。オーバーロード解決で演算子のオーバーロードされた関数呼び出しが選択された場合、代わりにその関数呼び出しの制限が適用されます。

これが、クラスタイプのオブジェクトをオブジェクトとして返すことが推奨される場合がある理由constです(例const foo q();)。ただし、これはC ++ 0xに悪影響を及ぼし、移動セマンティクスが正常に機能しなくなる可能性があります。

于 2011-05-24T14:26:20.557 に答える
8

構造体を割り当てることができq()、のコピーを返すstruct fooため、返された構造体を指定された値に割り当てます。

この場合、構造体は後でスコープから外れ、そもそも構造体への参照を保持しないため、(この特定のコードでは)何もできなかったため、これは実際には何もしません。

これはより理にかなっています(ただし、実際には「ベストプラクティス」ではありません)

struct foo
{
  int a;
};

foo* q() { foo *f = new malloc(sizeof(foo)); f->a = 4; return f; }

int main()
{
  foo i;
  i.a = 5;

  //sets the contents of the newly created foo
  //to the contents of your i variable
  (*(q())) = i;
}
于 2011-05-24T14:24:43.820 に答える
7

これの1つの興味深いアプリケーション:

void f(const std::string& x);
std::string g() { return "<tag>"; }

...

f(g() += "</tag>");

ここで、一時を変更します。これは、g()の戻り値に割り当てられたヒープに、を収容するのに十分な予備容量がg() +=ある可能性があるため、追加の一時を作成するよりも高速な場合があります。+</tag>

ideone.comでGCC/C++11を使用して実行されていることを確認してください。

さて、どのコンピューティング初心者が最適化と悪について何かを言いましたか...?;-]。

于 2011-05-25T04:12:28.453 に答える
0

On top of other good answers, I'd like to point out that std::tie works on top of this mechanism for unpacking data from another function. See here. So it's not error-prone per se, just keep in mind that it could be a useful design pattern

于 2021-11-27T19:45:37.880 に答える