当我运行程序时,一切正常。最后,它打印出以下内容:

*** glibc detected *** ./streamShare: double free or corruption (fasttop): 0x08292130 ***
======= Backtrace: =========
/lib/tls/i686/cmov/libc.so.6[0xcc2ff1]
/lib/tls/i686/cmov/libc.so.6[0xcc46f2]
/lib/tls/i686/cmov/libc.so.6(cfree+0x6d)[0xcc779d]
/usr/lib/libstdc++.so.6(_ZdlPv+0x21)[0x1c86f1]
./streamShare[0x804be7f]
./streamShare[0x804be3e]
./streamShare[0x804abc0]
./streamShare[0x804a5f2]
./streamShare[0x804a1c4]
./streamShare[0x804a1d7]
./streamShare[0x804a46a]
./streamShare[0x804ba45]
./streamShare[0x804b49c]
./streamShare[0x804ac68]
./streamShare[0x804ac48]
./streamShare[0x804a676]
./streamShare[0x804a237]
./streamShare[0x8049a3f]
./streamShare[0x804d2e5]
./streamShare[0x804d34d]
/lib/tls/i686/cmov/libc.so.6(__libc_start_main+0xe6)[0xc6eb56]
./streamShare[0x8049361]

我检查了一下,它是在函数返回时发生的,其中程序的所有对象都自动设置为无效。无论如何,我没有为这些对象定义任何析构函数,我尝试使用STL容器和TR1 shared_ptr。我猜一切都发生在默认析构函数中。有没有办法知道它在哪里分解?我的意思是,我想知道哪个对象破坏造成了整个困惑。我正在使用这些容器和共享的指针:
typedef std::tr1::shared_ptr<messageListener> mlsptr;

typedef std::map<const char*, mlsptr, ltstr> CONSTCHP2MSLST;

messageListener没有析构函数。以及其中两个 vector :
std::vector<MSG> queueto1;

MSG析构函数在哪里:
MSG::~MSG() {
    destroy();
}

void MSG::destroy() {
    if (payload != NULL)
        delete[] payload;
    payload = NULL;
    payloadLen = 0;
}

以前从来没有出现过问题,我这永远都不会...

有什么建议如何跟踪这个问题?我无能为力...

编辑:

此处为VALGRIND输出:
valgrind ./streamShare -v
==25795== Memcheck, a memory error detector
==25795== Copyright (C) 2002-2009, and GNU GPL'd, by Julian Seward et al.
==25795== Using Valgrind-3.5.0-Debian and LibVEX; rerun with -h for copyright info
==25795== Command: ./streamShare -v
==25795==
==25795== Invalid free() / delete / delete[]
==25795==    at 0x402454D: operator delete(void*) (vg_replace_malloc.c:346)
==25795==    by 0x804BCC0: std::tr1::_Sp_deleter<streamShare::messageListener>::operator()(streamShare::messageListener*) const (shared_ptr.h:97)
==25795==    by 0x804BC7F: std::tr1::_Sp_counted_base_impl<streamShare::messageListener*, std::tr1::_Sp_deleter<streamShare::messageListener>, (__gnu_cxx::_Lock_policy)2>::_M_dispose() (shared_ptr.h:75)
==25795==    by 0x804AAF7: std::tr1::_Sp_counted_base<(__gnu_cxx::_Lock_policy)2>::_M_release() (boost_sp_counted_base.h:140)
==25795==    by 0x804A58D: std::tr1::__shared_count<(__gnu_cxx::_Lock_policy)2>::~__shared_count() (shared_ptr.h:153)
==25795==    by 0x804A173: std::tr1::__shared_ptr<streamShare::messageListener, (__gnu_cxx::_Lock_policy)2>::~__shared_ptr() (shared_ptr.h:358)
==25795==    by 0x804A186: std::tr1::shared_ptr<streamShare::messageListener>::~shared_ptr() (shared_ptr.h:834)
==25795==    by 0x804A405: std::pair<char const* const, std::tr1::shared_ptr<streamShare::messageListener> >::~pair() (stl_pair.h:68)
==25795==    by 0x804D3D0: __gnu_cxx::new_allocator<std::pair<char const* const, std::tr1::shared_ptr<streamShare::messageListener> > >::destroy(std::pair<char const* const, std::tr1::shared_ptr<streamShare::messageListener> >*) (new_allocator.h:115)
==25795==    by 0x804D337: std::_Rb_tree<char const*, std::pair<char const* const, std::tr1::shared_ptr<streamShare::messageListener> >, std::_Select1st<std::pair<char const* const, std::tr1::shared_ptr<streamShare::messageListener> > >, streamShare::ltstr, std::allocator<std::pair<char const* const, std::tr1::shared_ptr<streamShare::messageListener> > > >::_M_destroy_node(std::_Rb_tree_node<std::pair<char const* const, std::tr1::shared_ptr<streamShare::messageListener> > >*) (stl_tree.h:383)
==25795==    by 0x804D29B: std::_Rb_tree<char const*, std::pair<char const* const, std::tr1::shared_ptr<streamShare::messageListener> >, std::_Select1st<std::pair<char const* const, std::tr1::shared_ptr<streamShare::messageListener> > >, streamShare::ltstr, std::allocator<std::pair<char const* const, std::tr1::shared_ptr<streamShare::messageListener> > > >::_M_erase(std::_Rb_tree_node<std::pair<char const* const, std::tr1::shared_ptr<streamShare::messageListener> > >*) (stl_tree.h:972)
==25795==    by 0x804D27B: std::_Rb_tree<char const*, std::pair<char const* const, std::tr1::shared_ptr<streamShare::messageListener> >, std::_Select1st<std::pair<char const* const, std::tr1::shared_ptr<streamShare::messageListener> > >, streamShare::ltstr, std::allocator<std::pair<char const* const, std::tr1::shared_ptr<streamShare::messageListener> > > >::_M_erase(std::_Rb_tree_node<std::pair<char const* const, std::tr1::shared_ptr<streamShare::messageListener> > >*) (stl_tree.h:970)
==25795==  Address 0x42c3358 is 0 bytes inside a block of size 8 free'd
==25795==    at 0x402454D: operator delete(void*) (vg_replace_malloc.c:346)
==25795==    by 0x804BCC0: std::tr1::_Sp_deleter<streamShare::messageListener>::operator()(streamShare::messageListener*) const (shared_ptr.h:97)
==25795==    by 0x804BC7F: std::tr1::_Sp_counted_base_impl<streamShare::messageListener*, std::tr1::_Sp_deleter<streamShare::messageListener>, (__gnu_cxx::_Lock_policy)2>::_M_dispose() (shared_ptr.h:75)
==25795==    by 0x804AAF7: std::tr1::_Sp_counted_base<(__gnu_cxx::_Lock_policy)2>::_M_release() (boost_sp_counted_base.h:140)
==25795==    by 0x804A58D: std::tr1::__shared_count<(__gnu_cxx::_Lock_policy)2>::~__shared_count() (shared_ptr.h:153)
==25795==    by 0x804A173: std::tr1::__shared_ptr<streamShare::messageListener, (__gnu_cxx::_Lock_policy)2>::~__shared_ptr() (shared_ptr.h:358)
==25795==    by 0x804A186: std::tr1::shared_ptr<streamShare::messageListener>::~shared_ptr() (shared_ptr.h:834)
==25795==    by 0x804A405: std::pair<char const* const, std::tr1::shared_ptr<streamShare::messageListener> >::~pair() (stl_pair.h:68)
==25795==    by 0x804D3D0: __gnu_cxx::new_allocator<std::pair<char const* const, std::tr1::shared_ptr<streamShare::messageListener> > >::destroy(std::pair<char const* const, std::tr1::shared_ptr<streamShare::messageListener> >*) (new_allocator.h:115)
==25795==    by 0x804D337: std::_Rb_tree<char const*, std::pair<char const* const, std::tr1::shared_ptr<streamShare::messageListener> >, std::_Select1st<std::pair<char const* const, std::tr1::shared_ptr<streamShare::messageListener> > >, streamShare::ltstr, std::allocator<std::pair<char const* const, std::tr1::shared_ptr<streamShare::messageListener> > > >::_M_destroy_node(std::_Rb_tree_node<std::pair<char const* const, std::tr1::shared_ptr<streamShare::messageListener> > >*) (stl_tree.h:383)
==25795==    by 0x804D29B: std::_Rb_tree<char const*, std::pair<char const* const, std::tr1::shared_ptr<streamShare::messageListener> >, std::_Select1st<std::pair<char const* const, std::tr1::shared_ptr<streamShare::messageListener> > >, streamShare::ltstr, std::allocator<std::pair<char const* const, std::tr1::shared_ptr<streamShare::messageListener> > > >::_M_erase(std::_Rb_tree_node<std::pair<char const* const, std::tr1::shared_ptr<streamShare::messageListener> > >*) (stl_tree.h:972)
==25795==    by 0x804D27B: std::_Rb_tree<char const*, std::pair<char const* const, std::tr1::shared_ptr<streamShare::messageListener> >, std::_Select1st<std::pair<char const* const, std::tr1::shared_ptr<streamShare::messageListener> > >, streamShare::ltstr, std::allocator<std::pair<char const* const, std::tr1::shared_ptr<streamShare::messageListener> > > >::_M_erase(std::_Rb_tree_node<std::pair<char const* const, std::tr1::shared_ptr<streamShare::messageListener> > >*) (stl_tree.h:970)
==25795==
==25795==
==25795== HEAP SUMMARY:
==25795==     in use at exit: 0 bytes in 0 blocks
==25795==   total heap usage: 22 allocs, 30 frees, 496 bytes allocated
==25795==
==25795== All heap blocks were freed -- no leaks are possible
==25795==
==25795== For counts of detected and suppressed errors, rerun with: -v
==25795== ERROR SUMMARY: 8 errors from 1 contexts (suppressed: 19 from 8)

最佳答案

从您的Valgrind输出判断,问题在于shared_ptr指向的对象被删除了两次。一种可能的方法是,如果您使用相同的原始指针初始化两个shared_ptr,例如:

int* p = new int(123);
shared_ptr<int> sp1(p);
shared_ptr<int> sp2(p);
shared_ptr并不是神奇的,它无法知道您要求它处理的对象是否已经由其他一些不相关的shared_ptr拥有,如果您提供的只是一个原始指针。在上面的示例中,每个shared_ptr将创建自己的引用计数器,并将其初始化为1;当它们死亡时,每个对象都会递减其自己的计数器,看到它为0,然后删除该对象,从而产生两次删除。我怀疑你的案子是相似的。如果显示用于初始化添加到 vector 的shared_ptr对象的代码,则可以对此进行验证。

[编辑] 由于现在已确认这是崩溃的原因,因此,我来​​详细说明一下
了解如何正确使用shared_ptr

首先,问题的性质。 shared_ptr的编写方式,可与任何C++类型一起使用,并提供引用计数语义。明显的问题是,大多数类型不提供任何空间来存储引用计数器(例如,考虑shared_ptr<int>-int内没有多余的空间)。要解决此问题,对于每个共享库,都会分配一个单独的内存块,其中包含引用计数器。每当您从原始指针创建shared_ptr时,就会完成此操作。然后,shared_ptr对象本身将存储原始的原始指针和指向引用计数器的指针(这就是为什么它比原始指针更“胖”的原因,可以使用sizeof对其进行简单检查)。当您从另一个创建shared_ptr(使用复制构造函数或赋值运算符)时,它会将指针复制到引用计数器,因此,彼此创建的所有shared_ptr实例都维护一个计数器,并保证正确删除。但是,如果您有两个不相关的shared_ptr对象“家族”到相同的对象(其中,两个或多个指针是从同一原始指针创建的),则这些“家族”彼此都不了解,并且将分别进行引用计数,并且每个引用达到0时删除。

实际上,这意味着在使用shared_ptr时,必须遵守某些规则。这些取决于您使用哪种实现。

对于std::tr1::shared_ptr或较早的Boost版本,唯一完全安全的对象分配模式是:
shared_ptr<T> x(new T(...));

换句话说,new的结果应立即放入shared_ptr中-然后您可以根据需要复制任意数量。

一个合理的安全模式也是这样的:
auto_ptr<T> x(new T);
...
shared_ptr<T> y(x);

shared_ptr初始化时,auto_ptr实现通常的所有权转移,并且后者的语义(只要正确遵循它们的语义)确保到对象的只存在一个auto_ptr。因此,从中构造一个shared_ptr是安全的。

有时,您还必须处理不使用auto_ptr指示指针所有权转移的C++库,而只需记录特定功能的意图即可。在这种情况下,使用shared_ptr也应该是安全的,但是当然,您应该确保已正确理解文档...

在C++ 0x std::shared_ptr和更高版本的boost::shared_ptr中,提供了helper来确保共享对象的正确实例化:
shared_ptr<int> p = make_shared<int>(123);
make_shared<T>()的返回类型已经是shared_ptr<T>,因此在任何时候您都不会处理代码中的原始指针,从而减少了出错的机会。

关于C++析构函数困惑,无法调试,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/1848575/

10-11 01:52
查看更多