Как исправить ошибку при попытке привязать ': basic_string ‹char› ›&' и ': basic_string ‹char››' в cpp?

Мой код не компилируется, и я не знаю, как это исправить. Похоже, проблема связана с оператором =, но я не уверен. Я пытаюсь применить заданную функцию к элементам отсортированного списка, чтобы получить другой отсортированный список, но в нем говорится, что я использую аргументы, отличные от ожидаемых. Мой код выглядит так:

#include <iostream>
#include <cstring>
#include <string>
#include <functional>

#include "dummy.h"
using namespace std;

#ifndef SORT_H
#define SORT_H

template <class T>
class LinkedList {
    struct Node {
        Node(const T &in) : data(in) {}
        T data;
        Node * next;
    };

    class Iterator
    {
        Node *m_ptr;              // pointer to current node in the list
    public:
        Iterator(Node * node) {
            m_ptr = node;
        }
        Iterator& operator ++ () {
            m_ptr = m_ptr -> next();
            return *this;
        }
        Iterator operator ++ (T) {
            Iterator temp(*this);
            m_ptr = m_ptr -> next();
            return temp;
        }
        bool operator == (const Iterator other) const {
            return m_ptr == other.m_ptr;
        }
        bool operator != (const Iterator other) const {
            return m_ptr != other.m_ptr;
        }
        T& operator * () {
            return m_ptr -> data();
        }
        operator bool() {
            return m_ptr != 0;
        }
    };

    Node * head;

    bool is_in_list(T value){
        Node * curr = head;
        while(curr != nullptr) {
            if (curr->data == value){
                return true;
            } else {
                curr = curr->next;
            }
        }
        return false;
    }


public:
    LinkedList() {
        head = nullptr;
    }
    LinkedList(T value) {
        head = new Node(value);
//        head -> data = value;
//        head -> next = nullptr;
    }

    ~LinkedList() {
        while(head != nullptr) {
            Node * curr = head -> next;
            delete head;
            head = curr;
        }
    }

    LinkedList operator = (LinkedList &list) {
        LinkedList<T> new_list(list);
        return new_list;
    }

    Node * nodeCopy(Node * head) {
        if (head == nullptr) {
            return nullptr;
        }
        Node * copied_node = new Node(head -> data);
        copied_node -> data = head -> data;
        copied_node -> next = nodeCopy(head -> next);
        return copied_node;
    }

    LinkedList(LinkedList &list){
        head = nodeCopy(list.head);
    }


    template<typename B>
    LinkedList filter(LinkedList &list, B pred) {
        LinkedList <T> new_list(list);
        Node * curr = list.head;
        while (curr) {
            if (!(pred(curr -> data))) {
                new_list.remove(curr -> data);
            }
            curr = curr -> next;
        }
        std::cout << "Getting out of filter" << std::endl;
        return new_list;
    }

    template<typename A>
    LinkedList apply(A func) {
        LinkedList <T> new_list;
        Node * curr = head;
        while (curr) {
            new_list.insert(func(curr -> data));
            std::cout << "Putting into new list: " << func(curr -> data) << std::endl;
            curr = curr -> next;
        }
        std::cout << "Getting out of apply" << std::endl;
        return new_list;
    }

    int length() {
//        std::cout << "DEBUG length 1" << std::endl;
        int counter = 0;
        Node * tmp = head;
//        std::cout << "DEBUG length 2" << std::endl;
        while( tmp != nullptr ) {
//            std::cout << "DEBUG length 3" << std::endl;
            counter++;
            tmp = tmp -> next;
        }
        return counter;
    }

    void insert(T value) {
        // Add first node
        if (head == nullptr) {
            std::cout << "Add first node" << std::endl;
            head = new Node(value);
            head->next = nullptr;
            return;
        }

        Node *curr = head;
        // check if should be new head (when new value smaller than current head) -> add new head
        if (value <= head->data) {
            // add new head
            std::cout << "add new head" << std::endl;
            Node * new_head = new Node(value);
            new_head -> next = head;
            head = new_head;
            return;
        }

        while (curr != nullptr) {
            if (curr->next == nullptr && value >= curr->data) {
                // add new tail
                std::cout << "add new tail" << std::endl;
                Node * new_node = new Node(value);
                curr -> next = new_node;
                new_node -> next = nullptr;
                return;
            } else if (value >= curr->data && value <= curr->next->data) {
                // add new node between those two
                std::cout << "add new node between those two" << std::endl;
                Node * new_node = new Node(value);
                Node * temp_ptr = curr -> next;
                curr -> next = new_node;
                new_node -> next = temp_ptr;
                return;
            } else {
                curr = curr->next;
            }
        }
    }

    void remove(T value) {
        // TODO: Check if delete all accurancies
        if (!is_in_list(value)){
            return;
        }

        // handle the head
        if (head->data == value) {
            if (head->next != nullptr) {
                // head is not single node
                Node * temp_ptr = head->next;
                delete head;
                head = temp_ptr;
                return;
            } else {
                // head is single node
                delete head;
                head = nullptr;
                return;
            }
        }

        Node * curr = head;
        Node * prev = head;
        while (curr != nullptr){
            if (curr -> data == value){
                // as we are already handled the head case,
                // at this point we know that curr != head.
                prev->next = curr->next;
                delete curr;
                return;
            } else {
                prev=curr;
                curr=curr->next;
            }
        }

    }

    void print() {
        Node * curr = head;
        while (curr != nullptr) {
            cout << curr -> data << endl;
            curr = curr -> next;
        }
    }

    Iterator begin() {
        return head;
    }
    Iterator end() {
        return Iterator(nullptr);
    }
};


#endif

А главное выглядит так -

#include <iostream>
#include "sortedList.h"
#include "dummy.h"

bool func(Dummy num) {
    int number = num.get();
    if (number % 2 != 0) {
        return false;
    }
    return true;
}

string getLen(string str)
{
    return std::to_string(str.length());
}

int main() {
    std::cout << "Hello, World!" << std::endl;

    LinkedList <string> myList;
    myList.insert("yosi");
    myList.insert("Rikki");
    myList.insert("Pavel <3");
    cout << "Now printing myList" << endl;
    myList.print();

    LinkedList<string> new_list;
    new_list = myList.apply(getLen);
    cout << "Now printing new_list" << endl;
    new_list.print();

    return 0;
}

Ошибка, которую я получаю, -

====================[ Build | exe_name | Debug ]================================
"C:\Program Files\JetBrains\CLion 2021.1.1\bin\cmake\win\bin\cmake.exe" --build C:\Users\User\CLionProjects\ex2.2\cmake-build-debug --target exe_name -- -j 3
Scanning dependencies of target exe_name
[ 33%] Building CXX object CMakeFiles/exe_name.dir/main.cpp.obj
[ 66%] Building CXX object CMakeFiles/exe_name.dir/sortedList.cpp.obj
C:\Users\User\CLionProjects\ex2.2\main.cpp: In function 'int main()':
C:\Users\User\CLionProjects\ex2.2\main.cpp:101:28: error: cannot bind non-const lvalue reference of type 'LinkedList<std::__cxx11::basic_string<char> >&' to an rvalue of type 'LinkedList<std::__cxx11::basic_string<char> >'
     new_list = myList.apply(getLen);
                ~~~~~~~~~~~~^~~~~~~~
In file included from C:\Users\User\CLionProjects\ex2.2\main.cpp:2:
C:\Users\User\CLionProjects\ex2.2\sortedList.h:83:16: note:   initializing argument 1 of 'LinkedList<T> LinkedList<T>::operator=(LinkedList<T>&) [with T = std::__cxx11::basic_string<char>]'
     LinkedList operator = (LinkedList &list) {
                ^~~~~~~~
mingw32-make.exe[3]: *** [CMakeFiles\exe_name.dir\build.make:81: CMakeFiles/exe_name.dir/main.cpp.obj] Error 1
mingw32-make.exe[3]: *** Waiting for unfinished jobs....
mingw32-make.exe[2]: *** [CMakeFiles\Makefile2:94: CMakeFiles/exe_name.dir/all] Error 2
mingw32-make.exe[1]: *** [CMakeFiles\Makefile2:101: CMakeFiles/exe_name.dir/rule] Error 2
mingw32-make.exe: *** [Makefile:136: exe_name] Error 2

Как я могу это исправить?


person SpaceNugget    schedule 12.06.2021    source источник
comment
LinkedList operator = (LinkedList &list) - FYI - Эта функция вызывает мгновенную утечку памяти. Что ты делал со старой памятью? Кроме того, ваш конструктор копирования обращается к неинициализированному указателю head.   -  person PaulMcKenzie    schedule 12.06.2021
comment
@PaulMcKenzie, почему? он просто копирует его, чтобы удерживать после того, как деструктор убьет исходный, не так ли?   -  person SpaceNugget    schedule 12.06.2021
comment
Ваш operator= должен возвращать ссылку на текущий объект, а не на новый объект. Это первая проблема. В противном случае вы злоупотребляете тем, что должен делать =, т.е. оператор присваивания. А если бы я сделал a = a; - что будет?   -  person PaulMcKenzie    schedule 12.06.2021
comment
LinkedList& operator =(LinkedList rhs) { std::swap(head, rhs.head); return *this;} Это, вероятно, решает всю проблему с оператором присваивания. См. идиому копирования и обмена.   -  person PaulMcKenzie    schedule 12.06.2021


Ответы (1)


Ваш оператор назначения копий доставляет вам проблемы.

Функция LinkedList apply(A func) возвращает (по значению) LinkedList, который затем, в свою очередь, используется в этой строке в _3 _...

new_list = myList.apply(getLen);

... для копирования-назначения вновь созданного экземпляра LinkedList new_list, (который был создан строкой выше).

Таким образом, вам необходимо включить в ваш LinkedList::operator= правильную логику, которая будет правильно обрабатывать выделенную память и вводить желаемую логику.

После рассмотрения этого и нескольких других ресурсов, я бы посоветовал вам придерживаться Идиома копирование и обмен, например:

LinkedList& operator = (LinkedList list) {
    std::swap(list.head, head); // if you don't define your own swap
    return *this;
}

Чтобы это сработало, вам также необходимо изменить конструктор копирования, как здесь:

LinkedList(const LinkedList &list){
    head = nodeCopy(list.head);
}

Итоговый пример вывода:

Hello, World!
Add first node
add new head
add new head
Now printing myList
Pavel <3
Rikki
yosi
Add first node
Putting into new list: 8
add new head
Putting into new list: 5
add new head
Putting into new list: 4
Getting out of apply
Now printing new_list
4
5
8
person rawrex    schedule 12.06.2021