在分配它的对象被销毁后,可以访问返回的LValue引用

时间:2013-10-04 02:37:03

标签: c++ reference lvalue

我无法理解为什么这段代码有效。我已经进入C#世界一段时间了,想要深入研究C / C ++,然后再深入研究C ++ 11中的新东西,比如RValue Refs和移动语义。

我想知道为什么我写的这段代码有效:

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。是否存在某种返回值优化?或者它是否真的返回副本而不是传回引用?

我使用GCC没有优化(-O0),它仍然没有问题。

我还使用-S开关来生成程序集,但我的AMD64知识生锈了,名称错误没有用。

3 个答案:

答案 0 :(得分:1)

这是未定义的行为,这意味着甚至可能发生“正确”的行为。当您在C ++中删除某些内容时,它不会从内存中删除,因此在其他内容写入之前访问它有时可能仍然有效。

答案 1 :(得分:0)

robjInner仍然是对内存中某些已删除对象的引用。 这将导致未定义的行为。

删除后,引用robjInner已悬空。你得到了之前的价值,因为还没有人声称那段记忆。

here

复制

以前有效的参考仅在两种情况下无效:

  1. 如果它引用了超出范围的自动分配对象,

  2. 如果它引用已释放的动态内存块中的对象。

  3. 如果引用具有静态作用域,则第一个很容易自动检测,但如果引用是动态分配对象的成员,则仍然存在问题;第二个更难以保证。这些是引用的唯一关注点,并且通过合理的分配策略适当地解决。

答案 2 :(得分:0)

您可以在InnerMember析构函数中添加print语句,以查看正在发生的事情。您会看到在TestClass之后销毁了InnerMember,而您获得的5是因为没有人写入该部分内存。但该参考不再有效。