为什么我可以在擦除后访问列表中对象的成员变量?

时间:2014-02-18 12:48:50

标签: c++ erase stdlist

#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,为什么?

3 个答案:

答案 0 :(得分:2)

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

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

答案 1 :(得分:0)

嗯,只要你已经分配了内存的那部分(无论是在堆栈上还是在堆上使用new / malloc),数据完整性都是有保证的。

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

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

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

答案 2 :(得分:0)

欢迎来到指针的狂野世界。你到底得到的是Dangling Pointer的情况(阅读维基文章,详细解释)。

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