【问题标题】:double dealloc problem while cleaning up a C++ STL list of pointers清理 C++ STL 指针列表时出现双重释放问题
【发布时间】:2010-08-16 11:45:08
【问题描述】:

问题:

我尝试释放由 STL 列表的指针项指向的内存。

这应该可以正常工作,但在我的情况下,列表中可能有重复的指针,即使我测试指针是否为 NULL,我也会得到一个双重 dealloc 异常(参见下面的源代码)。 我该如何解决这个问题?

环境:

  • Debian5 莱尼
  • gcc 版本 4.3.2 (Debian 4.3.2-1.1)
  • libc-2.7.so
  • libstdc++.so.6.0.10
  • Eclipse Galileo 构建 ID:20100218-1602 / CDT。

C++源代码:

list<Line *> * l = new list<Line *>;
Line * line = new Line(10, 10, 10, 10);
l->push_back(line);
l->push_back(line);

cout << "line addr " << line << endl;

for (list<Line *>::iterator it = l->begin(); it != l->end(); it++)
 {
  if (*it != NULL)
   {
    cout << "line it " << *it << " " << (*it)->toString() << endl;
    delete (*it);
    (*it) = NULL;
   }
 }
l->clear();

错误显示:

*** glibc detected *** /home/debian/workspace/Scrap/Release/Scrap: double free or corruption (!prev): 0x0846de20 ***
======= Backtrace: =========
/lib/i686/cmov/libc.so.6[0xb6d68764]
/lib/i686/cmov/libc.so.6(cfree+0x96)[0xb6d6a966]
/usr/lib/libstdc++.so.6(_ZdlPv+0x21)[0xb6f402e1]
/home/debian/workspace/Scrap/Release/Scrap[0x8067cb0]
/lib/i686/cmov/libc.so.6(__libc_start_main+0xe5)[0xb6d10455]
/home/debian/workspace/Scrap/Release/Scrap(_ZNSt8ios_base4InitD1Ev+0x49)[0x8052cd1]
======= Memory map: ========
08048000-0842c000 r-xp 00000000 08:01 3819374 /home/debian/workspace/Scrap/Release/Scrap
0842c000-08451000 rw-p 003e3000 08:01 3819374 /home/debian/workspace/Scrap/Release/Scrap

【问题讨论】:

  • 为什么要存储指针?标准容器是为对象设计的。

标签: c++ list pointers stl


【解决方案1】:

你可以使用智能指针而不是原始指针吗?我会尝试使用 boost shared_ptrs,如下所示:

#include <boost/shared_ptr.hpp>

list< boost::shared_ptr< Line > > l;
boost::shared_ptr< Line > line( new Line( 10, 10, 10, 10 ) );
l.push_back( line );
l.push_back( line );

当列表被销毁时,boost::shared_ptr 清理将删除 Line 对象。

【讨论】:

  • 非常感谢,这解决了我的问题!因为我已经在使用 libboost,这很好:)
【解决方案2】:
l->push_back(line);
l->push_back(line);

这只会插入 2 个指向同一个引用的指针。

delete (*it);

因此,当您为第一行调用此命令时,原始行将丢失。第二行现在将指向一个已释放的对象。


为什么不直接使用list&lt;Line&gt;(没有指针)?这完全避免了new/delete 问题,代价是存储按值。

或使用shared_ptr,如@Edric's answer

【讨论】:

    【解决方案3】:

    您可以创建临时 std::set,用原始容器中的项目填充它,并在循环中删除 set 的所有项目(set 保证我们将只有唯一的项目)。
    或者您可以将 std::unique 函数应用于您的容器。
    但我建议您使用智能指针(类似于 boost::shared_ptr)。他们将完成所有有关内存管理的工作。

    【讨论】:

      【解决方案4】:

      你只创建了一个线对象(只有一个新对象)

      但是您将其删除了两次,因为您将同一个对象两次放入列表中。

      做:

      Line * line = new Line(10, 10, 10, 10);
      l->push_back(line);
      line = new Line(10, 10, 10, 10);   // second new
      l->push_back(line);
      

      【讨论】:

        【解决方案5】:

        行被分配一次,但两次添加到您的列表中。第一次删除将释放分配的内存。第二次删除会抱怨它。这是完全正常的。

        考虑使用例如引用计数的智能指针而不是普通指针。

        【讨论】:

        • 感谢您的帮助,但是如果将指针设置为NULL,之后我们不会进入该条件,那将是正常的。相反,即使我将指针设置为 NULL,下一次迭代,它仍然认为它不为空,不?
        • 通过将指针设置为 NULL,实际上是在将列表的元素设置为 NULL。列表中的下一个条目仍将包含一个非 NULL 指针。
        猜你喜欢
        • 2010-09-23
        • 1970-01-01
        • 2017-11-17
        • 1970-01-01
        • 1970-01-01
        • 2016-05-23
        • 1970-01-01
        • 2018-03-20
        • 1970-01-01
        相关资源
        最近更新 更多