23

このオブジェクトへの参照を返すことは、代入演算子のオーバーロードでよく使用されます。また、setter メソッドへの一連の呼び出しによってオブジェクトを初期化できるようにする名前付きパラメーター イディオムのベースとしても使用されます。Params().SetX(1).SetY(1)各メソッドは *this への参照を返します。

しかし、への参照を返すのは正しいですか*this。一時オブジェクトの this への参照を返すメソッドを呼び出すとどうなるでしょうか。

#include <iostream>

class Obj
{
public:
    Obj(int n): member(n) {}
    Obj& Me() { return *this; }

    int member;
};

Obj MakeObj(int n)
{
    return Obj(n);
}

int main()
{
    // Are the following constructions are correct:
    std::cout << MakeObj(1).Me().member << std::endl;
    std::cout << Obj(2).Me().member << std::endl;
    Obj(3).Me() = Obj(4);

    return 0;
}
4

3 に答える 3

12

はい、*this を返却しても問題ありません。簡単なケースは、これが一時的なものではない場合ですが、一時的なものであっても、これは可能であるはずです:

一時オブジェクトは、それらが作成されたポイントを (レキシカルに) 含む完全な式 (1.9) を評価する最後のステップとして破棄されます。これは、その評価が例外のスローで終了した場合でも当てはまります (C++03 §12.2/3)。

言い換えれば、セミコロンに到達するまでは、(理論的には) すべて問題ないはずです。

したがって、次のコードが機能するはずです。

std::cout << MakeObj(1).Me().member << std::endl;

これはうまくいかないはずですが:

const Obj &MakeMeObj(int n) { return Obj(n).Me(); }
std::cout << MakeMeObj(1).member << std::endl;

一時への参照を返すため、これは論理的です。ほとんどのコンパイラはこれについて警告/エラーを出しますが、コードが複雑になる場合は注意が必要です。

個人的には、一時オブジェクトでこれらのメソッドを呼び出して、API ユーザーにオブジェクトの有効期間について考えるよう強制することは避けたいと思います。メソッドをオーバーロードすることでこれを行うことができます:(コンパイラがすでにサポートしている場合)

Obj &Me() & { return *this; }
Obj &Me() && = delete;
于 2016-02-27T12:55:58.007 に答える
6
// Are the following constructions are correct:
std::cout << MakeObj(1).Me().member << std::endl;
std::cout << Obj(2).Me().member << std::endl;

はい、各行ですべての一時オブジェクトの有効期間が延長され、完全な式が考慮されるためです。

cppreference.comが言うように:

(...) すべての一時オブジェクトは、それらが作成されたポイントを (字句的に) 含む完全な式を評価する最後のステップとして破棄されます (...)。

完全な式を分割しようとすると、(うまくいけば) コンパイラ エラーまたは警告が表示されます。

// not allowed:
Obj& ref = MakeObj(1);
std::cout << ref.Me().member << std::endl;

それ以外の場合、コンパイラは問題を認識し、診断メッセージを表示せずに実行可能ファイルを作成し、最終的に未定義の動作をプログラムに組み込むほど賢くない可能性があります。

// undefined behaviour:
Obj &ref = MakeObj(1).Me();
std::cout << ref.member << std::endl;
于 2016-02-27T12:11:03.267 に答える
5

はい、これは安全です。一時オブジェクトの存続期間は、ステートメントの終わり (より正確には、それが作成された完全な式の評価) までです。これは、標準によって保証されています。

12.2/3:一時オブジェクトは、それらが作成されたポイントを (レキシカルに) 含む完全な式を評価する最後のステップとして破棄されます。

参照にバインドされている場合、一部の条件下では一時的な有効期間が延長されることさえあります。しかし、ここで奇跡を期待しないでください。ステートメントを超えて参照を保持しようとすると (たとえば、アドレスを取得したり、参照を割り当てたりすることによって)、すぐに UB ( demo ) につながる可能性があります。

オブジェクトでこの種の構成を使用するconstと、非参照を返そうとするため、いくつかの問題も発生しますconst(ただし、これは代入とセッターの例では関係ありません)。

于 2016-02-27T12:06:21.823 に答える