web-dev-qa-db-ja.com

関数からローカル変数へのconst参照を返す

関数からローカル変数への参照を返すことについていくつか質問があります。

_class A {
public:
    A(int xx)
    : x(xx)
    {
        printf("A::A()\n");
    }
};

const A& getA1()
{
    A a(5);
    return a;
}

A& getA2()
{
    A a(5);
    return a;
}

A getA3()
{
    A a(5);
    return a;
}

int main()
{
    const A& newA1 = getA1(); //1
    A& newA2 = getA2(); //2
    A& newA3 = getA3(); //3
}
_

私の質問は=>

  1. getA1()の実装は正しいですか?ローカル変数または一時変数のアドレスを返すので、それは正しくないと感じます。

  2. main(1,2,3)のステートメントのうち、未定義の動作につながるのはどれですか?

  3. const A& newA1 = getA1();では、const参照によって一時的にバインドされたものは、参照がスコープ外になるまで破棄されないことが標準で保証されていますか?

37
aJ.

1. getA1()の実装は正しいですか?ローカル変数やテンポラリのアドレスを返すので間違っていると思います。

プログラムで正しいgetAx()のバージョンはgetA3()のみです。他の両方は、後でどのように使用しても、未定義の動作をします。

2. main(1,2,3)のどのステートメントが未定義の動作を引き起こしますか?

ある意味ではそれらのどれも。 1と2の場合、未定義の動作は関数の本体の結果です。最後の行では、一時を非const参照にバインドできないため、_newA3_はコンパイルエラーになります。

3. const A& newA1 = getA1();では、const参照によって一時的にバインドされたものが、参照がスコープ外になるまで破棄されないことが標準で保証されていますか?

いいえ。その例を次に示します。

_A const & newConstA3 = getA3 ();
_

ここで、getA3()は一時オブジェクトを返し、その一時オブジェクトの存続期間はオブジェクト_newConstA3_にバインドされています。言い換えると、_newConstA3_がスコープ外になるまで一時ファイルが存在します。

33
Richard Corden

Q1:はい、これは問題です。Q2の回答を参照してください。

Q2:1および2は、getA1およびgetA2のスタック上のローカル変数を参照するため、未定義です。これらの変数はスコープ外になり、使用できなくなります。スタックは常に変化しているため、上書きされる可能性があります。 getA3が機能するのは、戻り値のコピーが作成され、呼び出し元に返されるためです。

Q3:Q2への回答を見るためのそのような保証はありません。

4
dharga

主な問題は、一時的なものをまったく返さないことだと思います。

return A(5);

のではなく

A a(5);
return a;

それ以外の場合は、一時的ではなくローカル変数アドレスを返します。そして、temporary to const参照は一時的なものに対してのみ機能します。

私はそれがここで説明されていると思います: 一時的な定数参照

2
Arkaitz Jimenez

これをVC6でコンパイルすると、この警告が表示されます

******コンパイラ警告(レベル1)ローカル変数または一時オブジェクトのアドレスを返すC4172関数は、ローカル変数または一時オブジェクトのアドレスを返します。関数が戻ると、ローカル変数と一時オブジェクトが破棄されるため、返されるアドレスは無効です。******

この問題をテストしているときに、興味深いことがわかりました(与えられたコードはVC6で動作しています)。

 class MyClass
{
 public:
 MyClass()
 {
  objID=++cntr;
 }
MyClass& myFunc()
{
    MyClass obj;
    return obj;
}
 int objID;
 static int cntr;
};

int MyClass::cntr;

main()
{
 MyClass tseadf;
 cout<<(tseadf.myFunc()).objID<<endl;

}
0
Satbir