0

我无法理解为什么此代码有效。我在 C# 领域已经有一段时间了,想在深入研究 C++11 中的新东西(如 RValue Refs 和移动语义)之前复习 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。是否正在进行某种返回值优化?或者它真的返回一个副本而不是传回引用?

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

我还使用了 -S 开关来生成程序集,但我的 AMD64 知识已经生疏,而且名称修饰也没有帮助。

4

3 回答 3

1

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

于 2013-10-04T02:44:41.887 回答
0

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

删除后,引用 robjInner 一直悬空。你会取回之前的值,因为还没有其他人声称那块内存。

从这里复制

先前有效的引用仅在以下两种情况下无效:

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

  2. 如果它指的是已释放的动态内存块内的对象。

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

于 2013-10-04T02:44:09.063 回答
0

您可以在析构函数中添加打印语句InnerMember以查看发生了什么。你会看到 InnerMember 在 TestClass 之后被销毁,5你得到的是因为还没有人写入那部分内存。但该引用不再有效。

于 2013-10-04T02:46:18.273 回答