7
class Test {

public:

    int n1;

};

Test func() {

    return Test();

}

int main() {

    func() = Test();

}

これは私には意味がありません。これが許可される方法と理由は何ですか? 未定義の動作ですか?関数が右辺値を返す場合、右辺値を別の右辺値に設定するにはどうすればよいでしょうか? プリミティブ型でこれを試してみると、予想どおりのエラーが発生します。

左辺値はメモリ内の場所であることを知っているので、関数は一時的な左辺値 (右辺値?) を作成し、それを別の左辺値に割り当てますか? 誰かがこの構文がどのように機能するか説明できますか?

4

2 に答える 2

7

関数呼び出し式の値カテゴリは、実際には右辺値です。

実際、右辺値プリミティブでコピー代入演算子を呼び出すことはできません。C における右辺値の歴史的な定義は、実際には代入の左側にない可能性があるという区別でした。

ただし、クラスの代入演算子は少し異なります。それらは通常のメンバー関数です。また、右辺値のメンバー関数の呼び出しを妨げる規則はありません。実際、関数に副作用がある場合に非常に便利です。

それがどのように機能するか、まあ、コピー代入演算子が一時的に呼び出され、演算子は右側の引数をコピーして、一時的な状態を変更します。ステートメントの後、一時オブジェクトは破棄されます。UB はなく、無意味なコピーです。

次のような参照修飾子を使用して演算子を宣言することにより、右辺値でのコピー代入の呼び出しを防ぐことができTest& operator=(Test) & = default;ます。ref-qualifiers は c++11 で後から追加されたので、(暗黙の) コピー代入は以前は ref-qualified に指定できませんでした。おそらく、C++11 は暗黙のコピー コンストラクターの修飾子を変更せず、右辺値に代入する古いコードを壊さないようにしていましたが、そのような代入はまったく無意味に思えます。High Integrity C++ Coding Standardでは、ユーザー定義のコピー代入演算子で ref 修飾子を使用することを推奨しています。

于 2016-02-13T10:12:29.320 に答える
1

値カテゴリに関する限り、(少なくとも私にとっては)かなり急な学習曲線がありますが、例の用語を正しく理解していると思います。そう

func()

実際、prvalueを返し、C++ 標準の par から取得します。3.10.5 (私は現在のドラフトしか持っていません。段落番号は異なる場合があります) :

オブジェクトを変更するには、オブジェクトの左辺値が必要です。ただし、特定の状況下では、クラス型の右辺値を使用してその参照対象を変更することもできます。[例: オブジェクト (9.3) に対して呼び出されるメンバー関数は、オブジェクトを変更できます。— 最後の例]

したがって、メンバー関数である代入演算子は、標準で言及されている例のように、ルールの例外であり、右辺値を変更できます。

これは、プログラミングの世界で多くの批判を引き起こしました。最も極端な例は、次のC++ FQAの抜粋です。

(はい、砂糖でコーティングされた死の罠、無知なチアリーダー。X& obj=a.b().c()– おっと、b()一時オブジェクトであり、 c() はそれに参照を返します! それを参照に割り当てるべきではありませんでした. コンパイラの警告の可能性もあまりありません. )

しかし、実際の C++ プログラミングでは、名前付きパラメーターidiomのような産業用アプリケーションがあります。

std::cout << X::create().setA(10).setB('Z') << std::endl;
于 2016-02-13T12:25:46.123 に答える