문제

I'm having trouble understanding why this code works. I've been in the C# world for awhile and wanted to brush up on C/C++ before diving into the new stuff in C++11 like RValue Refs and move semantics.

I'm wondering why this code that I wrote works:

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;
}

The output is:

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

I thought that this would cause an error, since I access the referenced object InnerMember from TestClass after TestClass has been destroyed. Is there some sort of return value optimization going on? Or is it really returning a copy instead of passing back the reference?

I used GCC to with no optimizations (-O0) and it still ran without an issue.

I also used the -S switch to generate the assembly but my AMD64 knowledge is rusty and the name mangling didn't help.

도움이 되었습니까?

해결책 2

robjInner is still a reference to some deleted object in memory. This would lead to undefined behaviour.

After deletion, the reference robjInner has been left dangling. You get back the previous value because no one else claimed that piece of memory yet.

Copied from here

A previously-valid reference only becomes invalid in two cases:

  1. If it refers to an object with automatic allocation which goes out of scope,

  2. If it refers to an object inside a block of dynamic memory which has been freed.

The first is easy to detect automatically if the reference has static scoping, but is still a problem if the reference is a member of a dynamically allocated object; the second is more difficult to assure. These are the only concern with references, and are suitably addressed by a reasonable allocation policy.

다른 팁

That is undefined behaviour, which means even the "correct" behaviour could happen. When you delete something in C++, it is not erased from the memory, so accessing it before something else writes over it will sometimes maybe still work.

You can add a print statement inside InnerMember destructor to see what is going on. You will see InnerMember is destroyed after TestClass and the 5 you get is because no one write to that part of memory yet. But that reference is not valid anymore.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top