Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/135.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 回溯显示析构函数在陌生线路上调用的偶发性崩溃_C++_Segmentation Fault_Destructor - Fatal编程技术网

C++ 回溯显示析构函数在陌生线路上调用的偶发性崩溃

C++ 回溯显示析构函数在陌生线路上调用的偶发性崩溃,c++,segmentation-fault,destructor,C++,Segmentation Fault,Destructor,我有一个程序,通常运行得很好,但今天它在启动时崩溃了。之后立即再次运行它效果很好,所以很不幸,我不能给出一个简单的例子。但是,代码如下所示: #include "Configuration.hpp" #include "Program.hpp" int main() { ConfigurationReader confReader; // this is line 6, where gdb ind

我有一个程序,通常运行得很好,但今天它在启动时崩溃了。之后立即再次运行它效果很好,所以很不幸,我不能给出一个简单的例子。但是,代码如下所示:

    #include "Configuration.hpp"
    #include "Program.hpp"
  
    int main()
      {
         ConfigurationReader confReader; // this is line 6, where gdb indicates a 
                                         // segfault in the *destructor* of 
                                         // ConfigurationReader

         confReader.readConf();
         Conf & conf = confReader.getConf();
         Program program(conf);
         program.run();
 
        return 0;
     }
程序报告了一个SEGFULT,并在gdb中启动了核心。它说SEGFULT发生在上面代码示例中的第6行,在ConfigurationReader的析构函数中

当然,在这里调用析构函数是没有意义的,因为只有一个ConfigurationReader实例在浮动,在main结尾超出范围之前,它不应该进行析构函数。即使进行了积极的优化,在程序进行破坏之前,它也无法进行破坏,因为程序被传递到了对confReader内部某个东西的引用

问题:这里发生了或可能发生了什么?是否有一些我没有看到的未定义的行为?gdb的堆栈跟踪是否非常错误?我是否应该怀疑构建过程出了问题

注意:我知道在设计上最好不要让ConfigurationReader拥有它读入的Conf实例,但这不是这个问题的重点。请不要只是告诉我这样做而不回答实际问题

更新:正如John在评论中指出的,我还应该在这里提供一些关于ConfigurationReader::getConf的信息:

更新2:为了使代码示例可复制,我删除了行号,只添加了一条注释,指示gdb显示调用析构函数的位置


注2:正如我最初所说,不幸的是,我无法提供一个最小的可复制示例。我不能在玩具程序中重现这个问题。我甚至不能在真实的程序中重现这个问题;此崩溃只发生过一次。

仅凭您发布的代码,无法找出实际问题所在。因此,这不是对您的问题的回答,而是帮助您自己使用gdb找到解决方案的一种方法。不过,这是一个有点大的评论

在gdb中运行程序,并在main的最开始处停止。您可以使用“开始”命令进行此操作。现在在程序的最后一条指令处添加一个断点。您可以在gdb中使用b_exit实现这一点。只有当问题没有发生时,您的程序才应该达到此断点。当您在gdb中添加一个断点时,您会得到一个标识该断点的数字。假设_exit中的断点是断点2。您可以在gdb中添加命令,这些命令应该在命中某个特定断点时自动运行。使用命令2向断点2添加命令,键入run添加run命令,按ENTER键,键入end完成输入命令。现在键入run开始运行程序


这样,您的程序将在gdb中运行,如果没有发生错误,它将在命中最后一条指令时从头开始重新运行。当错误最终发生时,gdb将停止执行,您可以使用实际的进程而不仅仅是核心转储来调查问题。

我实际上能够在这里解决自己的问题,部分是为了回答PaulMcKenzie在评论中提出的问题。为了举例说明,这里有一个玩具程序:

class C { };

class D
{
  public:

    ~D()
    {
      int * p = nullptr;
      int x = *p;
    }
};

class E { };

class F { };

int main(int, char **)
{
  C c;
  D d; // this is line 21
  E e;
  F f;

  return 0;
}
当d自毁时,这当然会在main的末尾崩溃,因为我故意在自毁函数中放入一个segfault

如果我使用调试符号构建它,然后在gdb中运行它,我会得到以下回溯:

#0  0x00005555555546cc in D::~D (this=0x7fffffffde67, __in_chrg=<optimized out>) at program.cpp:10
#1  0x000055555555469a in main () at program.cpp:21
注意它在堆栈帧1中报告的行号。当然,在现实中,第22、23、24、25和26行已经完成,如果需要,我们可以通过登录来证明这一点

显然,gdb或负责将行号关联到编译器输出的工具的任何部分已经决定,当对象超出范围时,析构函数调用应该关联到最终导致它们的实际代码行,即构建对象的代码行


因此,我的程序中可能发生的情况是,程序完成了,而崩溃实际上发生在运行过程中,比预期的要晚得多。这是它自己的问题,因为program.run是一个没有退出条件的无限循环。由于ConfigurationReader的析构函数不可访问,而且以前从未运行过,因此它不能正常工作也就不足为奇了。

请按要求执行?您是否尝试过使用valgrind运行可执行文件?或者使用净化程序编译?getConf的返回类型是什么?之后立即再次运行它效果很好,所以很遗憾,我不能给出一个简单的示例-将代码发布到这些头中。您按原样发布的任何代码都不会产生任何错误。可能您有一个依赖于另一个要创建的全局对象的全局对象,但它没有被创建。另外,main实际上没有运行的证据在哪里?也许是一些问题导致了main的右转 直到最后,你认为这不会发生。
#0  0x00005555555546cc in D::~D (this=0x7fffffffde67, __in_chrg=<optimized out>) at program.cpp:10
#1  0x000055555555469a in main () at program.cpp:21