8

このようなことがC++で有効であることは誰もが知っています。

const T &x = T();

その間:

T &x = T();

ではありません。

最近の質問では、会話がこのルールにつながります。OPは、UBを明確に想起させるコードを投稿していました。しかし、私はそれの修正されたバージョンが機能することを期待していました(これは修正されたバージョンです):

#include <iostream>
using namespace std;

class A {
public:
    A(int k) { _k = k; };
    int get() const { return _k; };
    int _k;
};

class B {
public:
    B(const A& a) : _a(a) {}
    void b() { cout << _a.get(); }
    const A& _a;
};

B* f() {
    return new B(A(10));
}

int main() {
    f()->b();
}

これは、一部のマシンではゴミを印刷し、他のマシンでは10を印刷します...私にはUBのように聞こえます:-)。しかし、それから私は、それがそれを初期化してそれを読むことをするすべてAが基本的に栄光であると思いました。に電話して何が起こるか見てintみませんか:Aint

#include <iostream>
using namespace std;

typedef int A;

class B {
public:
    B(const A& a) : _a(a) {}
    void b() { cout << _a; }
    const A& _a;
};

B* f() {
    return new B(A(10));
}

int main() {
    f()->b();
}

10毎回印刷します。少なくとも、const参照ルールはバージョンに対して有効であるように見えintますが、クラスバージョンに対しては有効ではありません。ヒープを使用しているため、どちらも単にUBですか?intコンパイルがすべてをconst確認し、直接印刷したので、私はバージョンに幸運10ですか?ルールのどの側面が欠けていますか?

4

3 に答える 3

19

「コンパイラで試して」言語の動作を分析しても、通常は有用な結果が得られないことを単に示しています。両方の例は、まったく同じ理由で無効です。

一時の有効期間は、その一時を const 参照の直接初期化子として使用する場合にのみ延長されます。これにより、参照と一時の間の「有効期間」リンクが確立されます。

コンストラクターの引数として一時を渡そうとし、コンストラクター内で const 参照をアタッチすると、前述のリンクが確立されず、一時の有効期間が延長されません。

また、C++標準に従って、これを行うと

struct S {
  const int &r;

  S() : r(5) {
    cout << r; // OK
  }
};

一時的な有効期間は、コンストラクターの最後まで延長されます。コンストラクターが終了すると、一時的に終了します。つまり、これは

S s;
cout << s.r; // Invalid

無効です。

あなたの実験は、int単に「機能しているように見える」、純粋に偶然です。

于 2010-06-22T23:23:36.350 に答える
3

あなたはちょうど幸運になりました。B::b を次のように変更します。

void b() {
    int i = rand();
    int j = rand();
    cout << _a << endl;
}

乱数を出力します。

于 2010-06-22T23:26:18.370 に答える
3

毎回 10 を出力します。

main 関数を少し変更すると、10 が出力されなくなります。

int main()
{
    B* p = f();
    cout << "C++\n";   // prints C++
    p->b();            // prints 4077568
}

このリンクはどのレベルでどのように確立されますか?

12.2 [class.temporary] §4 および §5 を参照してください。

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

完全式の終わりとは異なる時点で一時変数が破棄される状況が 2 つあります。最初のコンテキストは [...]

2 番目のコンテキストは、参照がテンポラリにバインドされる場合です。参照がバインドされている一時、または参照がバインドされているサブオブジェクトの完全なオブジェクトである一時は、参照の存続期間中存続します。[...]

関数呼び出しの参照パラメーターへの一時的なバインドは、呼び出しを含む完全な式が完了するまで持続します。

したがって、あなたの場合、 full-expression の評価後に一時的なものは破棄されますnew B(A(10))

于 2010-06-22T23:27:57.797 に答える