1
#include <iostream>
using namespace std;

class X {
        public:
                X() {
                        cout<<"Cons"<<endl;
                }
                X(const X& x){
                        cout<<"Copy"<<endl;
                }
                void operator=(const X& x){
                        cout<<"Assignment called";
                }
};

X& fun() {
        X s;
        return s;
}

int main(){
        X s = fun();
        return 0;
}

このコードは、コピーコンストラクターも呼び出します。なぜこれが機能するのですか?このプログラムを初めて実行したとき、セグメントに障害が発生したことを思い出します。しかし、しばらくして、それはこのコピーの短所を呼び始めました。そして今は動作します!! Wierd。

しかし、私が置き換えると、fun()は次のようになります。

X fun() {
        X s;
        return s;
}

次に、短所をコピーします。は呼び出されません。コピーの短所だと思いました。この場合は呼び出されます。しかし、@ flyfishr64が指摘しているように、ここではRVOが登場します。しかし、それでも私が参照を返す場合については説明していません。私はそれが常にセグメンテーション違反であるべきだと思います。

説明はありますか?

4

4 に答える 4

4

これにより、メソッドが返されると存在しないスタック上のオブジェクトへの参照が返されます。スタックは巻き戻され、メモリはまだ存在しますが、使用しないでください。

X& fun() {
        X s;
        return s;
}

これを次のように変更すると:

X fun() {
        X s;
        return s;
}

これで、コピーが返されます。コンパイラが十分に賢い場合は、次のようになります。

X fun() {
    return X();
}

その場合、Xは呼び出し元のスタックに直接割り当てられるため、コピーは必要ありません。

セグメンテーション違反かどうかは、無効なメモリにアクセスしているかどうかによって異なります。

あなたの例では、構造から値にアクセスしません。segfaultを確認するには、最初にfun()変数を構造体に追加して返された参照を保持し、呼び出しXから戻った後、スタックにメモリを内部的に割り当て(でfun()使用される元のメモリを上書きする必要があります)、スタックに値を格納する別のメソッドを呼び出します(推奨) 0)。この2番目のメソッドが戻った後、 ...から返された元の参照を使用してから値を出力してみてください。XfunXfun

于 2009-11-27T04:35:13.580 に答える
2

このコードでは:

X fun() {
        X s;
        return s;
}

戻り値の最適化により、コンパイラーがローカル変数's'の作成をバイパスし、返された変数に直接Xを作成できるため、コピーコンストラクターは呼び出されません。

RVOについて詳しくはこちらをご覧ください

于 2009-11-27T04:31:09.370 に答える
2

@flyfishr64の答えを拡張するには

コピーコンストラクタは、次の理由でここで呼び出されます。

X s = fun();

初期化です。デフォルトのコンストラクターを呼び出すのではなく、fun()を使用してオブジェクトを構築しています。これは次と同等です。

X s(fun());

印刷された「短所」は、fun()のインスタンス用です。詳細については、この記事を参照してください:C++の代入演算子。

于 2009-11-27T04:35:08.707 に答える
0

そのようなローカル変数への参照を返すとき、あなたは未定義の振る舞いを呼び出しています。

class Xこの場合、実際にはポインタを使用する関数がないため、この場合は機能します。したがって、thisポインタが無効になっても問題ありません。

于 2010-01-28T13:52:27.757 に答える