链接列表中的C ++访问冲突读取位置

时间:2015-07-09 17:38:40

标签: c++ list

我最近一直试图解决this reddit challenge(问题的第2部分):

  

描述

     

感谢你给我的那份清单,我的想法更有条理!   我有一些问题虽然我认为你可以帮忙吗? >有时我将错误的信息放在列表项中。也许为了防止这种情况,我可以修改/更新列表项?这不是唯一的问题,但是当有50多个项目时,我的工作很难完成。你认为你可以添加分类我的项目的能力吗?显然,如果我有这个,我也希望能够按类别查看!   哦,最后,你们中的一些人真的很棒并且最后一次这样做但是有没有办法可以让我的列表保持状态,以便每次我再次打开电脑时都不需要重新键入它?   最新的待办事项列表应具有以下功能:   修改现有列表项   能够为列表项目提供类别。列表项应该能够采用任意数量的类别   按类别查看 - 所有列表项都应该能够按类别进行排序和输出,以便更容易通过提交进行   保留国家   谢谢!

     

正式输入&输出

     

输出描述

     

创建的任何输出都应该是用户友好的。当我查看我的待办事项列表时,我应该能够轻松地从另一个列表项中识别出一个列表项。   实例

     

(不要太过于字面意思,按照你想要的方式去做)   分类

     

输入:

     

类别输出

     

输入:   输出:       ---- ----编程        - 像素不是像素不是像素        - 计划编程语言        - C中的记忆        - 哈斯克尔音乐学院        - 来自一行代码的算法交响曲

     

---- ---- MUSIC        - 民间音乐模式        - 使用Melodic Minor Scale        - 哈斯克尔音乐学院        - 来自一行代码的算法交响曲

     

---- MUSIC&编程----        - 哈斯克尔音乐学院        - 来自一行代码的算法交响曲

修改项目

  

updateItem('用C创建正弦波','用Python创建正弦波');       //该项目现已从“在C中创建正弦波”变为“在Python中创建正弦波”。这应该反映在您创建的viewList函数/方法中。

我遇到的错误是我收到了“访问违规阅读位置”。那是因为在我的List<std::string>中,我在调整该列表的任何节点data = <Error reading characters of string>时已经意识到,但在退出ToDoList::addItem() data = "Take a shower"之前(或者任何数据必须等于)。

我希望我能正确解释我的问题。

#include <iostream>
#include <string>
#include <vector>

template<class T>
struct Node
{
    T data;
    Node* next = nullptr;
    Node();
    Node(T item);
};

template<class T>
Node<T>::Node()
{ }

template<class T>
Node<T>::Node(T item) : data(item)
{ }

template<class T>
class List
{
    Node<std::string>* head;
    Node<std::string>* tail;
    int size;

public:
    List();
    ~List();

    void addItem(T item);
    void deleteItem(T item);
    void display() const;
};
template<class T>
List<T>::List() : size(0)
{
    head = new Node<std::string>();
    tail = head;
}

template<class T>
List<T>::~List()
{
    auto* temp = head;
    for (int i = 0; i < size; ++i){
        head = head->next;
        delete temp;

        temp = head;
    }
}a

template<class T>
void List<T>::addItem(T item)
{
    tail->data = item;
    tail = tail->next = new Node<std::string>;
    size++;
}

template<class T>
void List<T>::deleteItem(T item)
{
    auto* temp = head;
    for (int i = 0; i < size; ++i){
        if (temp->data == item){
            if (temp == head){
                auto* h2 = head->next;
                delete temp;
                temp = 0;
                head = h2;
            }

            else if (temp == tail){
                delete temp;
                temp = 0;
            }

            else{
                temp->data = temp->next->data;
                auto* te = temp->next->next;
                delete temp->next;
                temp->next = 0;
                temp->next = te;
            }

            --size;
            break;
        }

        temp = temp->next;
    }
}

template <class T>
void List<T>::display() const
{
    auto* temp = head;
    for (int i = 0; i < size; ++i)
    {
        std::cout << "- " << temp->data;
        temp = temp->next;
    }
}

class Category
{
    std::string name;
    List<std::string> list;

public:
    Category(std::string name);

    void addItemToCategory(std::string item);
    void doneItemInCategory(std::string item);
    void displayCategory() const;

    std::string getName() const;
};

Category::Category(std::string _name) : name(_name)
{ }

void Category::addItemToCategory(std::string item)
{
    list.addItem(item);
}

void Category::doneItemInCategory(std::string item)
{
    list.deleteItem(item);
}

void Category::displayCategory() const
{
    list.display();
}

std::string Category::getName() const
{
    return name; 
}

class ToDoList 
{
    std::vector<Category> categories;

public:
    ToDoList();

    void addItem(std::string item, std::string category);

    void viewList();
};

ToDoList::ToDoList()
{ }

void ToDoList::addItem(std::string item, std::string category)
{
    if (!categories.size()){
        Category newCategory(category);
        newCategory.addItemToCategory(item);

        categories.push_back(newCategory);
    }
    else{
        for (auto& cate : categories){
            if (cate.getName() == category){
                cate.addItemToCategory(item);
                return;
            }
        }

        Category newCategory(category);
        newCategory.addItemToCategory(item);

        categories.push_back(newCategory);
    }
}

void ToDoList::viewList()
{
    for (const auto& cate : categories){
        std::cout << "------" << cate.getName() << "------\n";
        cate.displayCategory();
    }
    std::cout << "\n" <<std::endl ;
}

int main()
{
    ToDoList list;

    list.addItem("Take a shower", "x");
    list.addItem("Go to work", "x");
    list.viewList();

    list.addItem("Buy a new phone", "y");
    list.viewList();

    std::cin.ignore(2);
}

1 个答案:

答案 0 :(得分:0)

我建议您阅读rule of 5。基本上,通过为List定义析构函数但不声明任何复制/移动构造函数,您已经做到了这样做任何类型的复制/移动都是危险的并且会将List放入一个无法使用的状态。具体来说,看看这个:

if (!categories.size()){
    Category newCategory(category);
    newCategory.addItemToCategory(item);

    categories.push_back(newCategory);
}

这里发生了什么?您构造newCategory,将其复制到categories,然后销毁它。由于你还没有定义任何拷贝构造函数,这是一个浅拷贝 - 它只是复制你的指针值,而不是对它们指向的内存做任何事情。当你摧毁它时会发生什么? ~Category()运行,调用~List(),删除所有Node。既然你已经释放了那段记忆,categories中的东西就指向了垃圾。

要解决此问题,您可以为List定义复制构造函数,以便分配新的Node并复制所有数据。理想情况下,您也可以定义移动构造函数,这样您就可以安全地执行此操作,而无需额外的内存分配。