调试断言失败

4
当我的程序结束时,我得到了“调试断言失败”的错误。我一直在尝试修复它,但始终找不到原因。即使是我的大学教授也说看不出有什么问题。所以你是我的最后希望,求助于stackoverllow。请帮忙。
该程序查找两个列表的交集,然后检查第三个列表是否是交集的子集。
错误截图:
代码: list.h:
#ifndef __LIST_H_INCLUDED__
#define __LIST_H_INCLUDED__
#include <string>
#include <iostream>
#include <fstream>

struct node
{
    int value;
    node *next;
};

class list
{
    node* head;
public:
    list();
    ~list();
    void AddNodes(std::istream &input);
    void PrintList(std::ostream &output = std::cout);
    void AddOneNode(int AddVal);
    node* RetHead();
    list* Intersection(list* list2);
    bool IsPresent(int val);
    bool Subset(list subset);
 };

 #endif

list.cpp:

#include "stdafx.h"
#include "list.h"
#include <iostream>
#include <fstream>


list::list()
{
    head=NULL;
}

list::~list()
{

    node* current = head;
    while( current != 0 ) 
    {
        node* next = current->next;
        delete current;
        current = next;
    }
    head = 0;

}

void list::AddNodes(std::istream &input)
{
    int InVal;
    while(input>>InVal)
        AddOneNode(InVal);
}

void list::AddOneNode(int AddVal)
{
    node *NewNode= new node;
    NewNode->value=AddVal;
    NewNode->next=NULL;
    if(!head)
        head=NewNode;
    else
        {
            node *temp=head;
            while(temp->next)
                temp=temp->next;
            temp->next=NewNode;
        }
}

void list::PrintList(std::ostream &output)
{
    node *temp=head;
    while(temp)
    {
        output<<temp->value<<std::endl;
        temp=temp->next;

    }
}

list* list::Intersection(list *list2)
{
    list* result=new list;
    node* temp1=head;
    while(temp1)
    {
        if(list2->IsPresent(temp1->value))
            result->AddOneNode(temp1->value);
        temp1=temp1->next;

    }
    return result;
}

bool list::IsPresent(int val)
{
    node *temp=head;
    while(temp)
    {
        if(temp->value==val)
            return true;
        temp=temp->next;
    }
    return false;
}


bool list::Subset(list subset) // head=set
{
    bool flag;
    node* tempset=head;
    node* tempsub=subset.RetHead();
    while(tempset)
    {
        if (tempsub->value==tempset->value)
        {
            flag=true;
            break;
        }
        tempset=tempset->next;
    }
    if (!tempset)
        return false;
    while(tempsub)
    {
        tempsub=tempsub->next;
        if(!tempsub)
            return true;
        while(tempsub->value!=tempset->value&&tempset)
            tempset=tempset->next;
        if(!tempset)
            return false;
    }
    return flag;
}

node* list::RetHead()
{
    return head;
}

main.cpp:

#include "stdafx.h"
#include "list.h"
#include <Windows.h>
#include <fstream>

list Cross (list list1, list list2);
bool Subset (list set, list subset);

int main()
{
    setlocale (LC_ALL, "Russian");
    list l1,l2,l3;
    std::ifstream fl1 ("l1.txt");
    std::ifstream fl2 ("l2.txt");
    std::ifstream fl3 ("l3.txt");
    l1.AddNodes(fl1);
    std::cout<<"List 1:"<<std::endl;
    l1.PrintList();
    std::cout<<std::endl;
    l2.AddNodes(fl2);
    std::cout<<"List 2:"<<std::endl;
    l2.PrintList();
    std::cout<<std::endl;
    l3.AddNodes(fl3);
    std::cout<<"List 3:"<<std::endl;
    l3.PrintList();
    std::cout<<"Intersection of list 1 and list 2"<<std::endl;
    list *intersec=l1.Intersection(&l2);
    intersec->PrintList();
    std::cout<<std::endl;
    if(intersec->Subset(l3))
        std::cout<<"Third set is a subset of the intersection"<<std::endl;
    else
        std::cout<<"Third set is not a subset of the intersection"<<std::endl;
    system("pause");
    return 0;
}

1
你的包含保护符使用了保留标识符。而且你也没有遵循三大法则之一(真的,不要使用拥有原始指针)。 - chris
你的输入数据是什么? - Captain Obvlious
你很可能正在“双重释放”某个东西。 - Mats Petersson
1
@Creris,我不认为这是原因,但这绝对不是一个好主意。 - chris
@chris 不是我的问题,但我还是很好奇,头文件保护的更好命名是什么?我个人使用一个下划线和全大写标识符,但我认为这些也是保留的。我知道在别人的问题上问这个问题有点不好,但总的来说这是一个离题的问题。 - Creris
显示剩余4条评论
1个回答

9
问题在于函数list::Subset(list subset)按值传递参数,导致list的副本被制作。由于您没有遵循三法则(如Chris的评论中所述),因此进行了浅拷贝。这意味着两个list实例“拥有”指针。当Subset函数返回时,副本超出范围会导致节点被删除。当程序退出时,原始list的副本超出范围,并且它尝试再次删除相同的节点,导致断言。

您可以通过按引用而不是按值获取参数来解决此问题。更改

class list
{
    // ... snip ...
    bool Subset(list subset);
    // ... snip ...
};

转换为

class list
{
    // ... snip ...
    bool Subset(list& subset);
    // ... snip ...
};

并且

bool list::Subset(list subset)
{
    // ... snip ...
}

to

bool list::Subset(list& subset)
{
    // ... snip ...
}

其他一些建议:

  1. 要么实现一个适当的拷贝构造函数,要么声明一个并将其设置为私有,以防止复制操作。
  2. 学习使用 const。由于 Subset 不会修改传递给它的列表的内容,因此可以将其声明为 bool list::Subset(const list&) const。这也需要将 list::RetHead() 声明为 const
  3. list::Subset 中的 bool flag 没有初始化,这意味着如果逻辑不正确,则可以返回任何值。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接