析构函数结束时的分段错误

bar*_*gol 7 c++ destructor segmentation-fault

我不知道这个问题是否会明确,因为我不能提供太多细节(我正在使用TPL并且自己写了大量的行).但我会试一试.

我遇到了一个我无法理解的分段错误.有一个结构(我没有设计但应该经过充分测试),其析构函数看起来像这样

Data::~Data()
{
  if(A_ != 0) {
    delete A_;
    A_ = 0;
  }

  if(B_ != 0) {
    delete B_;
    B_ = 0;
  }

  if(C_ != 0) {
    delete C_;
    C_ = 0;
  }
} // HERE
Run Code Online (Sandbox Code Playgroud)

令我困扰的是,在调试时,我得到了段错误发生在标有"HERE"的行.类Data只有A_,B_和C_作为动态分配的属性.我还尝试在其他非动态复合属性上显式调用析构函数,以查看在销毁过程中是否出现错误,但是在析构函数结束时又发生了段错误.什么样的错误可以在这一点上产生段错误?

我希望这个问题很清楚,如果需要我会添加细节.

编辑:谢谢你的回复.我知道这是一段稀疏的代码,但整个库当然太大了(顺便说一下,它来自Trilinos,但我认为错误不是他们的错,在处理他们的结构时一定是我的错误.我使用过短名称,以保持问题更紧凑).有人在评论中回答说:

  • 关于删除之前的检查和原始指针:正如我所说,这不是我的选择.我猜这是一个双重保护,以防出现问题,A_,B_或C_已经被数据结构的其他所有者删除了.选择原始指针vs shared_ptr或其他安全/智能指针可能是因为这个类几乎从不直接使用,而只是由具有指向Data的指针的Map类的对象.这个类Map在同一个库中实现,因此他们可能选择了原始指针,因为他们知道他们正在处理什么以及如何处理.
  • 是的,数据结构由同一对象的所有副本共享.特别是,有一个Map类,它包含一个指向Data对象的指针.所有Map都是彼此的副本,共享相同的数据.引用计数器跟踪有多少Map持有指向数据的指针.要销毁的最后一个Map删除数据.
  • 数据结构的引用计数器正常工作,我检查了它.
  • 我不是在叫这个类的析构函数.它由类Map的对象的析构函数自动调用,该对象具有指向Data作为属性的指针.
  • 数据继承自BaseData,其(虚拟)析构函数不执行任何操作,因为它只是一个定义类的接口.
  • 发布重现问题的代码很难.因为许多的原因.该错误仅出现在2个以上的进程(这是一个mpi程序),我猜它是一个进程有一些空的列表并尝试访问某个元素.
  • 关于错误细节.我可以在这里给你在调试过程中错误的回溯中的最后一项(我为糟糕的格式道歉,但我不知道如何把它很好地说):

    1. 加密中的0x00007ffff432fba5(sig =)at ../nptl/sysdeps/unix/sysv/linux/raise.c:64

    2. 在abort.c:92中的abort()中的0x00007ffff43336b0

    3. 0x00007ffff436965b在__libc_message(do_abort =,FMT =)在../sysdeps/unix/sysv/linux/libc_fatal.c:189

    4. 0x00007ffff43736d6在malloc_printerr:在malloc.c(动作= 3,STR = 0x7ffff4447780 "免费()损坏未分选的块",PTR =):6283

    5. 位于malloc.c的__libc_free(mem =)中的0x00007ffff4379ea3:3738

    6. 0x0000000000c21f71在Epetra_BlockMapData ::〜Epetra_BlockMapData(这= 0x1461690,__in_chrg =)在/home/bartgol/LifeV/trilinos/trilinos-10.6.4-src/packages/epetra/src/Epetra_BlockMapData.cpp:110

最后,让我重申一下我的疑问:即使所有属性都已被删除,析构函数的结尾会出现什么样的错误?再次感谢!

Ant*_*ony 5

这可能会导致一个问题段错误在函数退出是堆或堆栈损坏.

程序的某些其他部分可能会导致问题.像双重破坏缓冲区溢出之类的东西会导致内存损坏.

通常,程序的调试版本将包括在函数出口处检查以确保堆栈完好无损.如果不是,那么,你会看到结果.