当我运行程序时,一切正常。最后,它打印出以下内容:
*** 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/