当前位置:  开发笔记 > 编程语言 > 正文

c ++析构函数一塌糊涂,无法调试

如何解决《c++析构函数一塌糊涂,无法调试》经验,为你挑选了1个好方法。

当我运行我的程序时,一切都很顺利.最后打印出来:

*** 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 mlsptr;

typedef std::map CONSTCHP2MSLST;

messageListener没有析构函数.其中两个向量:

std::vector 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::operator()(streamShare::messageListener*) const (shared_ptr.h:97)
==25795==    by 0x804BC7F: std::tr1::_Sp_counted_base_impl, (__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::~__shared_ptr() (shared_ptr.h:358)
==25795==    by 0x804A186: std::tr1::shared_ptr::~shared_ptr() (shared_ptr.h:834)
==25795==    by 0x804A405: std::pair >::~pair() (stl_pair.h:68)
==25795==    by 0x804D3D0: __gnu_cxx::new_allocator > >::destroy(std::pair >*) (new_allocator.h:115)
==25795==    by 0x804D337: std::_Rb_tree >, std::_Select1st > >, streamShare::ltstr, std::allocator > > >::_M_destroy_node(std::_Rb_tree_node > >*) (stl_tree.h:383)
==25795==    by 0x804D29B: std::_Rb_tree >, std::_Select1st > >, streamShare::ltstr, std::allocator > > >::_M_erase(std::_Rb_tree_node > >*) (stl_tree.h:972)
==25795==    by 0x804D27B: std::_Rb_tree >, std::_Select1st > >, streamShare::ltstr, std::allocator > > >::_M_erase(std::_Rb_tree_node > >*) (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::operator()(streamShare::messageListener*) const (shared_ptr.h:97)
==25795==    by 0x804BC7F: std::tr1::_Sp_counted_base_impl, (__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::~__shared_ptr() (shared_ptr.h:358)
==25795==    by 0x804A186: std::tr1::shared_ptr::~shared_ptr() (shared_ptr.h:834)
==25795==    by 0x804A405: std::pair >::~pair() (stl_pair.h:68)
==25795==    by 0x804D3D0: __gnu_cxx::new_allocator > >::destroy(std::pair >*) (new_allocator.h:115)
==25795==    by 0x804D337: std::_Rb_tree >, std::_Select1st > >, streamShare::ltstr, std::allocator > > >::_M_destroy_node(std::_Rb_tree_node > >*) (stl_tree.h:383)
==25795==    by 0x804D29B: std::_Rb_tree >, std::_Select1st > >, streamShare::ltstr, std::allocator > > >::_M_erase(std::_Rb_tree_node > >*) (stl_tree.h:972)
==25795==    by 0x804D27B: std::_Rb_tree >, std::_Select1st > >, streamShare::ltstr, std::allocator > > >::_M_erase(std::_Rb_tree_node > >*) (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)

Pavel Minaev.. 28

根据您的Valgrind输出判断,问题是a指向的对象shared_ptr被删除两次.获得这种情况的一种可能性是,如果shared_ptr使用相同的原始指针初始化两个,例如:

int* p = new int(123);
shared_ptr sp1(p);
shared_ptr sp2(p);

shared_ptr不是神奇的,它不知道你要求它照顾的对象是否已经被其他一些无关的对象所拥有shared_ptr,如果所有你给它的是一个原始指针.在上面的例子中,每个shared_ptr都会创建自己的引用计数器,初始化为1; 当它们死亡时,每个都会减少它自己的计数器,看它是0,并删除该对象,产生双重删除.我怀疑你的情况类似.如果显示用于初始化shared_ptr添加到向量的对象的代码,则可以验证此代码.

[编辑]由于这被证实是现在崩溃的原因,让我详细说明如何正确使用shared_ptr.

首先,问题的本质.shared_ptr编写方式,它适用于任何C++类型,并提供引用计数语义.显而易见的问题是大多数类型都没有提供任何空间来存储引用计数器(例如考虑shared_ptr- 内部没有额外的空间int).要解决此问题,请为每个共享对象分配一个包含引用计数器的单独内存块.无论何时shared_ptr从原始指针创建,都会执行此操作.然后,shared_ptr对象本身存储原始的原始指针,以及指向引用计数器的指针(这就是为什么它比原始指针"胖"的原因,可以通过简单的方式检查sizeof).当您shared_ptr从另一个创建一个(使用复制构造函数或赋值运算符)时,它会将指针复制到引用计数器,因此所有shared_ptr彼此创建的实例都会维护一个计数器,并保证正确删除.但是如果你有两个不相关的"族" shared_ptr对象到同一个对象(其中两个或多个指针是从同一个原始指针创建的),那些"家族"彼此不知道,并将单独引用,每个都将删除当它达到0.

这在实践中意味着,在使用时shared_ptr,必须遵守某些规则.这些取决于您使用的实现.

使用std::tr1::shared_ptr或更旧的Boost版本,唯一完全安全的对象分配模式是:

shared_ptr x(new T(...));

换句话说,new应该立即将结果放入shared_ptr- 然后您可以根据需要复制后者.

一个相当安全的模式也是这样的:

auto_ptr x(new T);
...
shared_ptr y(x);

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

有时您还必须处理C++库,这些库不用于auto_ptr指示指针所有权的传输,而只是记录特定函数的意图.在这些情况下,它也应该是安全的shared_ptr,但当然你应该确保你已正确理解文档......

在C++ 0x中std::shared_ptr,在较新版本中boost::shared_ptr,提供了一个帮助程序来确保共享对象的正确实例化:

shared_ptr p = make_shared(123);

返回类型make_shared()已经存在shared_ptr,所以在任何时候你都不会处理代码中的原始指针,从而减少出错的可能性.



1> Pavel Minaev..:

根据您的Valgrind输出判断,问题是a指向的对象shared_ptr被删除两次.获得这种情况的一种可能性是,如果shared_ptr使用相同的原始指针初始化两个,例如:

int* p = new int(123);
shared_ptr sp1(p);
shared_ptr sp2(p);

shared_ptr不是神奇的,它不知道你要求它照顾的对象是否已经被其他一些无关的对象所拥有shared_ptr,如果所有你给它的是一个原始指针.在上面的例子中,每个shared_ptr都会创建自己的引用计数器,初始化为1; 当它们死亡时,每个都会减少它自己的计数器,看它是0,并删除该对象,产生双重删除.我怀疑你的情况类似.如果显示用于初始化shared_ptr添加到向量的对象的代码,则可以验证此代码.

[编辑]由于这被证实是现在崩溃的原因,让我详细说明如何正确使用shared_ptr.

首先,问题的本质.shared_ptr编写方式,它适用于任何C++类型,并提供引用计数语义.显而易见的问题是大多数类型都没有提供任何空间来存储引用计数器(例如考虑shared_ptr- 内部没有额外的空间int).要解决此问题,请为每个共享对象分配一个包含引用计数器的单独内存块.无论何时shared_ptr从原始指针创建,都会执行此操作.然后,shared_ptr对象本身存储原始的原始指针,以及指向引用计数器的指针(这就是为什么它比原始指针"胖"的原因,可以通过简单的方式检查sizeof).当您shared_ptr从另一个创建一个(使用复制构造函数或赋值运算符)时,它会将指针复制到引用计数器,因此所有shared_ptr彼此创建的实例都会维护一个计数器,并保证正确删除.但是如果你有两个不相关的"族" shared_ptr对象到同一个对象(其中两个或多个指针是从同一个原始指针创建的),那些"家族"彼此不知道,并将单独引用,每个都将删除当它达到0.

这在实践中意味着,在使用时shared_ptr,必须遵守某些规则.这些取决于您使用的实现.

使用std::tr1::shared_ptr或更旧的Boost版本,唯一完全安全的对象分配模式是:

shared_ptr x(new T(...));

换句话说,new应该立即将结果放入shared_ptr- 然后您可以根据需要复制后者.

一个相当安全的模式也是这样的:

auto_ptr x(new T);
...
shared_ptr y(x);

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

有时您还必须处理C++库,这些库不用于auto_ptr指示指针所有权的传输,而只是记录特定函数的意图.在这些情况下,它也应该是安全的shared_ptr,但当然你应该确保你已正确理解文档......

在C++ 0x中std::shared_ptr,在较新版本中boost::shared_ptr,提供了一个帮助程序来确保共享对象的正确实例化:

shared_ptr p = make_shared(123);

返回类型make_shared()已经存在shared_ptr,所以在任何时候你都不会处理代码中的原始指针,从而减少出错的可能性.

推荐阅读
无名有名我无名_593
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有