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

标签 c++ list

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

Description

Thanks for that list you made me, my thoughts are way more organised! I've got a few problems though that I thought you might be able to help with? >Sometimes I put the wrong information in a list item. Maybe to prevent this I'd be able to modify/update the list item? That's not the only problem though, when there are 50+ items it gets kind of hard to work my way through. Do you think you could maybe add the ability to categorise my items? Obviously, if I have that, I'd also like to be able to view by category! Oh and finally, a few of you were really great and did this last time but is there a way you can somehow make my list retain state so that I don't have to re-type it everytime I turn my computer on again? The newest To-do list should be capable of the following functionality: Modifying an existing list item Be able to give a list item a category. The list item should be able to take an arbitrary amount of categorys View by category - All list items should be able to be sorted and output by category to make it easier to wade through submissions Retain state Thanks!

Formal Inputs & Outputs

Output description

Any output that is created should be user-friendly. When I'm viewing my to-do list, I should be able to easily discern one list item from another. Examples

(don't take this too literally, do it how you would like to do it) Categorisation

Input:

Category Output

Input: Output: ----PROGRAMMING---- - A pixel is not a pixel is not a pixel - The Scheme Programming Language - Memory in C - Haskell's School of Music - Algorithmic Symphonies from one line of code

----MUSIC---- - Modes in Folk Music - The use of the Melodic Minor Scale - Haskell's School of Music - Algorithmic Symphonies from one line of code

----MUSIC & PROGRAMMING---- - Haskell's School of Music - Algorithmic Symphonies from one line of code

修改项目

updateItem('Create Sine Waves in C', 'Create Sine Waves in Python'); //The item has now changed from 'Create Sine Waves in C' to 'Create Sine Waves in Python'. This should be reflected in the viewList function/method you have created.

我遇到的错误是我收到“访问违规阅读位置”。那是因为在我的 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);
}

最佳答案

我建议您阅读 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 并复制所有数据。理想情况下,您还可以定义移动构造函数,这样您就可以安全地执行此操作,而无需分配额外的内存。

关于C++链表中的访问冲突读取位置,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31324556/

相关文章:

c# - 清除和替换是否比循环检查所有记录更有效?

c++ - 用 C/C++ for windows 开发时省略 msvcr100.dll?

c++ - 使用C++在OS X上动态链接SQLCipher

c++ - 是否有一个 c++ 库可以在跨平台应用程序中包含 flash 视频?

c - 带有 bug 的链表的哈希表

python - 从元组列表中为每个项目创建 np.arrays 的最快方法

c++ - 如何在 C++ 中打开文件(即 .txt 文件)(有点像在 Windows 中双击它)?

c++ - 必须使用 'class' 标记来引用此范围内的类型 '____'

list - 使用 List-entrys Groovy 进行模式匹配的优雅方式

java - 将图像插入 JList