C++ 添加析构函数逻辑会导致分段错误

C++ 添加析构函数逻辑会导致分段错误,c++,segmentation-fault,C++,Segmentation Fault,有几个问题已经有了类似的标题,但我一直无法找到一个在析构函数未调用时出现seg故障的问题 我一直在写一个模板化的双链接列表(为了好玩和练习),到目前为止,它工作正常(到处都是插入和删除测试,测试边缘情况等) 到目前为止,我还没有正确地实现RAII,因此现在实际使用它是非常不安全的(拷贝将是一个问题,除非您首先清除列表,否则如果超出范围,它将像翻转的存储桶一样泄漏内存) 我最初有一个空的析构函数: template<class T> dll<T>::~dll() {} t

有几个问题已经有了类似的标题,但我一直无法找到一个在析构函数未调用时出现seg故障的问题

我一直在写一个模板化的双链接列表(为了好玩和练习),到目前为止,它工作正常(到处都是插入和删除测试,测试边缘情况等)

到目前为止,我还没有正确地实现RAII,因此现在实际使用它是非常不安全的(拷贝将是一个问题,除非您首先清除列表,否则如果超出范围,它将像翻转的存储桶一样泄漏内存)

我最初有一个空的析构函数:

template<class T>
dll<T>::~dll()
{}
template<class T>
dll<T>::~dll()
{
    while ( del_node(0) ){}    //returns 0 if no nodes left to delete.
}
my(未更改)
find_node()
函数导致seg故障

由于对代码的唯一更改是在析构函数中,我“假设”它是相关的,但我不知道如何更改。由于dll对象位于堆栈上,并且在main结束之前一直在作用域中,因此不应调用析构函数

使用空析构函数,代码按预期运行

以下是当前的示例代码:

dll_example.cpp:

#include <iostream>
#include <climits>
#include "dll.h"

void printout(dll<int> list)
{
    std::cout<<"\nnumber of nodes: "<<list.get_node_count()<<std::endl;
    std::cout<<"list contents:"<<std::endl;
    list.print_list();
}

int main()
{
    dll<int> list;

    std::cout<<"created list" << std::endl;

    for (int i = 0; i<10; i++)
    {
        int j = list.add_node(i, 5);
        std::cout<<"added a node, value: "<<i<<", index: "<< j << std::endl;
    }

    printout(list);

    std::cout<<"\nfinding '8'" << std::endl;                    //Prints this line
    int index = list.find_node(8);                           
    std::cout<<"deleting '8' (index: "<<index<<")"<< std::endl; //never gets this far
    list.del_node(index);

    printout(list);

    std::cout<<"\ndeleting #1" << std::endl;
    list.del_node(1);

    printout(list);

    std::cout<<"\ndeleting #0" << std::endl;

    do{                                     //manually delete all entries including 
                                            //a del_node() call on empty list (works)
      printout(list);
      std::cout<<"deleting #0" << std::endl;
    }while(list.del_node(0));
    printout(list);
}
空析构函数输出:

...
list contents:
0, 1, 2, 3, 4, 9, 8, 7, 6, 5,

finding '8'
deleting '8' (index: 6)

number of nodes: 9
list contents:
0, 1, 2, 3, 4, 9, 7, 6, 5,
...

在我看来,
printout()
是罪魁祸首。您直接传递列表,它将调用复制构造函数。除非您明确定义了复制构造函数,否则您将获得默认值,它将执行浅层复制。我看到
find_node()
中引用了指向
dllnode
s的指针。默认的浅层复制只会复制顶级指针,这意味着
printout()
中的新
dll
将与
main()
中的外部有效负载具有相同的
dllnode
s有效负载。当
printout()
返回时,这些文件将被删除,将外部文件留在
main()
中,指针悬空,导致seg故障

快速修复。将
printlist()
的声明更改为:

void printout(dll<int> &list)
void打印输出(dll和列表)
这将通过引用传递列表,这将(a)更快,(b)不会调用复制构造函数并导致调用析构函数

在任何情况下,您都应该创建一个复制构造函数,也可能是一个
操作符=
,这两个操作符都需要进行深度复制,即复制
dllnode
s的整个列表。有很多方法可以使用,在这种情况下,这些方法的默认(浅层)方法将导致各种各样的问题

void printout(dll<int> list)
这将使用复制构造函数传递参数

如果复制构造函数与析构函数不匹配,则会发生不好的事情

如果希望在不实现复制构造函数和复制赋值运算符的情况下使用类,最好在不实现它们的情况下将它们声明为
private

template<class T>
class dll {
 private:
   dll(dll&);             // no implementation
   void operator=(dll&);  // no implementation
 ...
模板
类dll{
私人:
dll(dll&);//没有实现
void运算符=(dll&);//无实现
...

一旦你不小心使用了复制构造函数,编译器就会对你大喊大叫。

“和一个正在工作的del_节点”函数它实际上是做什么的?你正在按值将一个列表传递给
打印输出。这将使用你的复制构造函数和析构函数。三的规则不会原谅,三的规则不会忘记(当你从另一个角度看的时候,它就变成了五条规则。)尊重它。@n.m.我不敢相信我错过了。只是改成了
printout(list&list)
,它就起作用了——这是因为现在没有复制构造函数,对吗?(facepalm,我说过这是为了练习,对吧?)。把它作为答案贴出来,我会接受的
void printout(dll<int> list)
printout(list);
template<class T>
class dll {
 private:
   dll(dll&);             // no implementation
   void operator=(dll&);  // no implementation
 ...