0

このコードが機能する理由を理解できません。私はしばらくの間 C# の世界にいましたが、RValue Refs やムーブ セマンティクスなどの C++11 の新しい機能に飛び込む前に、C/C++ をブラッシュ アップしたいと考えていました。

私が書いたこのコードがなぜ機能するのか疑問に思っています:

class InnerMember
{
    private:
        int _iValue;

    public:
        InnerMember(): _iValue(0) {};
        InnerMember(int iValue) : _iValue (iValue) {};

        int GetValue(void) { return _iValue; }
        int SetValue(int iValue) { _iValue = iValue; }
};

class TestClass
{
    private:
        InnerMember _objValue;

    public:
        TestClass() : _objValue(1) {};

        void SetValue(int iValue)
        {
            _objValue.SetValue(iValue);
        }

        InnerMember& GetRef(void)
        {
            return _objValue;
        }

        virtual ~TestClass() { std::cout << "I've been released!" << std::endl; }
};

int main (int argc, char *argv[])
{

    TestClass* pobjTest = new TestClass();

    std::cout << "Before:" << std::endl;
    std::cout << pobjTest->GetRef().GetValue() << std::endl;

    pobjTest->SetValue(5);

    InnerMember& robjInner = pobjTest->GetRef();

    delete pobjTest;

    std::cout << "After:" << std::endl;
    std::cout << robjInner.GetValue();

    return 0;
}

出力は次のとおりです。

Before:
1
I've been released!
After:
5
Press any key to continue...

TestClass が破棄された後、TestClass から参照先の InnerMember にアクセスするので、これはエラーになると思いました。ある種の戻り値の最適化が行われていますか? それとも、参照を返すのではなく、本当にコピーを返していますか?

最適化なし (-O0) で GCC を使用しましたが、問題なく動作しました。

また、-S スイッチを使用してアセンブリを生成しましたが、AMD64 の知識が不足しており、名前の変更は役に立ちませんでした。

4

3 に答える 3

1

これは未定義の動作であり、「正しい」動作でさえ発生する可能性があることを意味します。C++ で何かを削除しても、それはメモリから消去されないため、他の何かが上書きする前にアクセスしても機能する場合があります。

于 2013-10-04T02:44:41.887 に答える
0

robjInner は、メモリ内の削除されたオブジェクトへの参照のままです。これにより、未定義の動作が発生します。

削除後、参照 robjInner はぶら下がったままになっています。他の誰もまだそのメモリの一部を要求していないため、以前の値が返されます。

ここからコピペ

以前有効だった参照が無効になるのは、次の 2 つの場合のみです。

  1. 範囲外の自動割付オブジェクトを参照した場合、

  2. 解放された動的メモリのブロック内のオブジェクトを参照している場合。

1 つ目は、参照に静的なスコープがある場合は自動的に簡単に検出できますが、参照が動的に割り当てられたオブジェクトのメンバーである場合は依然として問題になります。2 つ目は、保証するのがより困難です。これらは参照に関する唯一の懸念事項であり、合理的な割り当てポリシーによって適切に対処されます。

于 2013-10-04T02:44:09.063 に答える
0

InnerMemberデストラクタ内に print ステートメントを追加して、何が起こっているかを確認できます。TestClass の後に InnerMember が破棄されていることがわかります。これ5は、メモリのその部分にまだ誰も書き込みを行っていないためです。しかし、その参照はもはや有効ではありません。

于 2013-10-04T02:46:18.273 に答える