1
#include <list>
#include <iostream>

struct Foo
{
    Foo(int a):m_a(a)
    {}
    ~Foo()
    {
        std::cout << "Foo destructor" << std::endl;
    }
    int m_a;
};

int main( )
{
   std::list<Foo> a;
   Foo b(10);
   std::cout << &b << std::endl;
   a.push_back(b);
   Foo* c = &(*a.begin());
   std::cout << c << std::endl;
   a.erase(a.begin());
   std::cout << a.size() << std::endl;
   c->m_a = 20;
   std::cout << c->m_a << std::endl;
   std::cout << b.m_a << std::endl;
}

结果是:

0x7fff9920ee70
0x1036020
Foo destructor
0
20
10
Foo destructor

我通常认为在删除列表中的对象后,我无法再访问 thar 对象的成员变量。但是在上面我c->m_a删除了c指向的对象后仍然可以访问,为什么?

4

3 回答 3

2

Foo* c = &(*a.begin());您创建了一个指向您有意销毁的对象的指针(通过erase())。但是,对象的内存仍然存在(因为这是一个非常简单的应用程序,并且操作系统没有为其他东西声明它)。

因此,您可以有效地使用不再属于您的内存。

于 2014-02-18T13:03:19.887 回答
0

欢迎来到指针的狂野世界。你在这里得到的是Dangling Pointer的情况(阅读 wiki 文章,它详细解释了它)。

基本上这里发生的是,从列表中删除项目后,指针c变成了悬空指针(它是指向不再被Foo对象占用的内存位置的指针)。但是 C++ 仍然允许你通过这个指针读/写,但是副作用将是完全不确定的(意味着任何事情都可能发生)。由于代码很简单,因此在测试代码期间您很幸运(或者很不幸,因为这些类型的问题随着时间的推移会变得非常困难和危险)。

于 2014-02-18T13:23:56.333 回答
0

好吧,只有在您分配了那部分内存(无论是在堆栈上还是在使用 new/malloc 的堆上),才能保证数据完整性。

释放数据后,数据会发生什么情况是未定义的(这意味着它取决于实现)。释放内存的最有效方法是简单地将内存标记为可用,将数据留在那里,直到另一个程序使用 malloc 声明这部分内存并覆盖它。这就是大多数实现将如何处理这个问题。

C++ 不会检查您正在读取或写入的数据是否属于您的程序。这就是为什么当您的程序尝试将数据写入内存中它无权访问的位置时会出现分段错误的原因。

在您的情况下,您将释放内存,然后立即检查其值。C++ 将愉快地执行您的代码。由于您最近才释放它,因此您的数据仍然存在的可能性非常高(但肯定不能保证:迟早会被覆盖)。

于 2014-02-18T13:08:55.823 回答