0 / 0 / 0
Регистрация: 14.05.2020
Сообщений: 50
1

Шаблонный класс двусвязного списка и rvalue ссылки

08.05.2021, 01:07. Показов 3051. Ответов 14

Пишу шаблонный класс двусвязного списка. Возникла два вопроса. Первый вопрос: правильно ли я присвоил rvalue значение в поле data класса List_node? (строка 70 в реализации списка). Второй вопрос: В чем заключается ошибка? Компилятор ругается на строку 138, в которой я создаю новый элемент двусвязного списка. Компилировал с помощью утилиты make
Код
rm -f ./objects/main.o
rm -f main
g++ -Wall -Wextra -Werror -g -std=c++17 -o objects/main.o -c main.cpp
In file included from main.cpp:2:
./headers/doubly_linked_list.hpp: In instantiation of ‘void List<T>::push_back(T&&) [with T = int]’:
main.cpp:8:23:   required from here
./headers/doubly_linked_list.hpp:138:11: error: cannot bind rvalue reference of type ‘int&&’ to lvalue of type ‘int’
  138 |  new_node = __create_node(value);
./headers/doubly_linked_list.hpp:63:42: note:   initializing argument 1 of ‘List_node<T>* List<T>::__create_node(T&&) [with T = int]’
   63 | List_node<T> *List<T>::__create_node(T&& value)
      |                                      ~~~~^~~~~
make: *** [Makefile:24: objects/main.o] Error 1
Код двусвязного списка:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
#pragma once
 
#include <ostream>
#include <list>
 
/* Doubly linked list node class */
 
template <typename T>
class   List_node
{
private:
    T           *data;
    List_node   *prev_ptr;
    List_node   *next_ptr;
 
template <typename U> friend class List;
};
 
/* Doubly linked list class */
 
template <typename T> 
class   List
{
private:
    List_node<T>    *head;
 
    List_node<T>    *__create_node(T&& value);
 
public:
    List();
    ~List();
 
    size_t          size();
    bool            empty();
    void            clear();
    void            print(std::ostream& outstream);
    void            push_back(T&& value);
};
 
template <typename T>
List<T>::List()
{
    head = nullptr;
}
 
template <typename T>
List<T>::~List()
{
    List_node<T>    *temp_ptr;
 
    if (head != nullptr)
    {
        while (head->next_ptr != nullptr)
        {
            temp_ptr = head;
            head = head->next_ptr;
            delete temp_ptr;
        }
    }
}
 
template <typename T>
List_node<T>    *List<T>::__create_node(T&& value)
{
    List_node<T>    *new_node;
    
    new_node = new List_node<T>;
    if (new_node)
    {
        new_node->data = &value;
        new_node->next_ptr = nullptr;
        new_node->prev_ptr = nullptr;
    }
    return (new_node);
}
 
template <typename T>
bool    List<T>::empty()
{
    return (head == nullptr);
}
 
template <typename T>
size_t  List<T>::size()
{
    List_node<T>    *temp_ptr;
    size_t          size = 0;
 
    if (head == nullptr)
        return (0);
    temp_ptr = head;
    while (temp_ptr != nullptr)
        size++;
    return (size);
}
 
template <typename T>
void    List<T>::clear()
{
    List_node<T>    *temp_ptr;
 
    if (head != nullptr)
    {
        while (head->next_ptr != nullptr)
        {
            temp_ptr = head;
            head = head->next_ptr;
            delete temp_ptr;
        }
    }
    head = nullptr;
}
 
template <typename T>
void    List<T>::print(std::ostream& outstream)
 
{
    List_node<T>    *temp_ptr;
 
    if (!head)
        return ;
    temp_ptr = head;
    while (temp_ptr->next_ptr != nullptr)
    {
        outstream << *(temp_ptr->data) << " ";
        temp_ptr = temp_ptr->next_ptr;
    }
    outstream << "\n";
}
 
template <typename T>
void    List<T>::push_back(T&& value)
{
    List_node<T>    *new_node;
    List_node<T>    *curr_node;
    List_node<T>    *prev_node;
 
    new_node = __create_node(value);
    if (new_node != nullptr)
    {
        if (!head)
        {
            head = new_node;
            return ;
        }
        else
        {
            curr_node = head;
            while (curr_node->next_ptr != nullptr)
            {
                prev_node = curr_node;
                curr_node = curr_node->next_ptr;
            }
            curr_node->next_ptr = new_node;
            if (curr_node != head)
                curr_node->prev_ptr = prev_node;
        }
    }
}
Код внутри мейна:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <iostream>
#include "./headers/doubly_linked_list.hpp"
 
int main()
{
    List<int>   new_list;
 
    new_list.push_back(12);
    new_list.push_back(14);
    new_list.push_back(1552);
 
    new_list.print(std::cout);
 
    return (0);
}
__________________
Помощь в написании контрольных, курсовых и дипломных работ, диссертаций здесь
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
08.05.2021, 01:07
Ответы с готовыми решениями:

Есть класс двусвязного списка(head,tail),как разделить его на два списка
Есть класс двусвязного списка(head,tail),как разделить его на два списка(отрицательные и...

Создать динамический класс Route на основе двусвязного списка, где каждый элемент типа stop (стоп). Класс должен содержа
Здравствуйте,вот такие задачи в универе... Кто-то может понять что тут делать? Задача на с++...

Класс, шаблонный класс, на основе списка
Не знаю как создать класс Deque на основе списка с дополнительными наборами методов class Deque...

Динамический класс на основе двусвязного списка
Здравствуйте,вот такие задачи в универе... Кто-то может понять что тут делать? Создать...

14
129 / 81 / 49
Регистрация: 10.01.2020
Сообщений: 293
08.05.2021, 09:09 2
newmersedez, 138 строка:
C++
1
new_node = __create_node(static_cast<T&&>(value));
Также, в этом же методе у вас есть потенциальная вероятность не инициализировать переменную-указатель prev_node
1
Вездепух
Эксперт CЭксперт С++
10428 / 5698 / 1552
Регистрация: 18.10.2014
Сообщений: 14,067
08.05.2021, 09:16 3
Цитата Сообщение от newmersedez Посмотреть сообщение
Первый вопрос: правильно ли я присвоил rvalue значение в поле data класса List_node? (строка 70 в реализации списка).
Нет, не правильно. Автор очевидно попытался воспользоваться rvalue ссылками для того, чтобы обойти ограничения языка и упростить самому себе создание мертвых указателей "в никуда". Именно такие мертвые указатели "в никуда" и создаются в этом коде.

Почему элементы списка содержат указатели на данные? Откуда возникла такая странная идея хранить указатели? Куда эти указатели будут указывать? Кто и как будет заботиться о времени жизни указуемых данных?

Пока что написана полная бессмыслица.
1
129 / 81 / 49
Регистрация: 10.01.2020
Сообщений: 293
08.05.2021, 09:27 4
newmersedez, Пример структуры реализации шаблонного двухсвязного списка:
Node:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
template <typename T> class DoubleLinkedListNode
    {
        template<typename T> friend class DoubleLinkedList;
        
 
    public:
        DoubleLinkedListNode(T otherValue = T(), DoubleLinkedListNode* otherpPrev = nullptr, DoubleLinkedListNode* otherpNext = nullptr);
 
        T& GetValue()
        {
            return this->m_Value;
        }
 
    private:
 
        DoubleLinkedListNode* pPrev;
        DoubleLinkedListNode* pNext;
        T m_Value;
    };
 
    template<typename T>
    inline DoubleLinkedListNode<T>::DoubleLinkedListNode(T otherValue, DoubleLinkedListNode* otherpPrev, DoubleLinkedListNode* otherpNext)
    {
        this->m_Value = otherValue;
        this->pPrev = otherpPrev;
        this->pNext = otherpNext;
    }
List:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
template <typename T> class DoubleLinkedList
    {
    public:
        DoubleLinkedList()
    {
        this->m_pHead = nullptr;
        this->m_pTail = nullptr;
        this->m_iSize = 0;
    }
        class iterator
        {
        public:
 
            iterator()
            {
                this->m_pCurrent = nullptr;
            }
 
            
 
        private:
 
            DoubleLinkedListNode<T>* m_pCurrent;
        };
 
    private:
 
        DoubleLinkedListNode<T>* m_pHead;
        DoubleLinkedListNode<T>* m_pTail;
        int m_iSize;
        }
Добавлено через 4 минуты
Также, тут нет деструктора, но он обязателен.
1
0 / 0 / 0
Регистрация: 14.05.2020
Сообщений: 50
08.05.2021, 13:02  [ТС] 5
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Почему элементы списка содержат указатели на данные?
Такое задание в курсовой, нельзя хранить копии. Если буду хранить копии, заставят переписать

Добавлено через 1 минуту
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Нет, не правильно. Автор очевидно попытался воспользоваться rvalue ссылками для того, чтобы обойти ограничения языка и упростить самому себе создание мертвых указателей "в никуда". Именно такие мертвые указатели "в никуда" и создаются в этом коде.
Тогда как правильно присвоить значение rvalue ссылки в поле класса?
0
129 / 81 / 49
Регистрация: 10.01.2020
Сообщений: 293
08.05.2021, 13:03 6
TheCalligrapher,
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Почему элементы списка содержат указатели на данные?
С другой стороны это верно, ведь если в данных узла будет лежать, скажем, большая структура данных, то каждый раз для нее будет задействован конструктор копирования, что увеличит расход памяти программы.
1
16495 / 8988 / 2205
Регистрация: 30.01.2014
Сообщений: 15,603
08.05.2021, 13:19 7
Лучший ответ Сообщение было отмечено newmersedez как решение

Решение

Цитата Сообщение от newmersedez Посмотреть сообщение
нельзя хранить копии.
Тогда вам надо определиться где будут храниться эти экземпляры ваших данных, чтобы указатели на них можно было сохранять в списке.
Т.е. ответить для себя вот на эти вопросы:
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Куда эти указатели будут указывать? Кто и как будет заботиться о времени жизни указуемых данных?
Добавлено через 14 минут
Цитата Сообщение от stdin Посмотреть сообщение
каждый раз для нее будет задействован конструктор копирования
Хранить отдельно указатели на данные эффективно только если эти данные у нас уже где-то созданы и живут по крайней мере столько же, сколько сам список. Если ТС как-то это обеспечит, тогда ок. В остальных случаях это не будет ничем лучше, а вот хуже - запросто.
1
0 / 0 / 0
Регистрация: 14.05.2020
Сообщений: 50
08.05.2021, 13:36  [ТС] 8
Да, у меня в дальнейшем в этом списке будут храниться объекты другого класса, скажем так, таких объектов может быть больше 20 миллионов. Поэтому я и храню указатель, чтобы не хранить копию объекта и сам объект
0
129 / 81 / 49
Регистрация: 10.01.2020
Сообщений: 293
08.05.2021, 13:39 9
newmersedez, Тогда почему бы вам шаблонно не задать указательный тип. List<Type*> lst; где Type - нужный вам тип.
1
16495 / 8988 / 2205
Регистрация: 30.01.2014
Сообщений: 15,603
08.05.2021, 13:40 10
newmersedez, а где эти 20 миллионов объектов тогда будут храниться?
1
0 / 0 / 0
Регистрация: 14.05.2020
Сообщений: 50
08.05.2021, 13:44  [ТС] 11
Думаю, что вы правы

Добавлено через 2 минуты
Ну скорее всего не так много, но сам список будет достаточно большим, поэтому и решил указатель хранить уже на существующие обьекты
0
16495 / 8988 / 2205
Регистрация: 30.01.2014
Сообщений: 15,603
08.05.2021, 13:49 12
Цитата Сообщение от newmersedez Посмотреть сообщение
решил указатель хранить уже на существующие обьекты
Это нормально, но вы все-таки должны определиться где они реально существовать будут. От этого зависит корректное выполнение вашего задания.
1
Вездепух
Эксперт CЭксперт С++
10428 / 5698 / 1552
Регистрация: 18.10.2014
Сообщений: 14,067
08.05.2021, 17:21 13
Лучший ответ Сообщение было отмечено newmersedez как решение

Решение

Цитата Сообщение от newmersedez Посмотреть сообщение
Такое задание в курсовой
Почему мы только сейчас узнаем детали задания?

Цитата Сообщение от newmersedez Посмотреть сообщение
нельзя хранить копии. Если буду хранить копии, заставят переписать
Это какая-то дичь.

Во-первых, контейнер всегда будет хранить копии. Копии чего-то: копии объектов или копии указателей на объекты. Это всегда будут копии. Вопрос лишь что за копии это будут.

Во-вторых, ваш контейнер параметризован параметром T - типом хранимых данных. Если вы хотите хранить в вашем контейнере указатели - пожалуйста, храните, никто вам не запретит. Но для этого не нужно прошивать эту "указательность" прямо в реализацию шаблона. Для это достаточно просто использовать указательный тип в качестве T при инстанцировании шаблона, точно так же как это делается со стандартными контейнерами.

Например, стандартный контейнер std::list<T> хранит в своих элементах значения типа T, а не T *. Тем не менее, никто мне не запрещает создать std::list<int *> - список, который будет хранить указатели. Чем вас не устраивает такой, намного более логичный подход?

Цитата Сообщение от newmersedez Посмотреть сообщение
Тогда как правильно присвоить значение rvalue ссылки в поле класса?
В-третьих, если вам по какой-то дикой причине захотелось реализовать контейнер с намертво прошитой в нем "указтельностью" хранимых данных, то флаг вам в руки. Но при чем здесь вообще какие-то "rvalue ссылки"? Откуда они тут взялись и зачем вы их сюда приплели? Ваш контейнер хранит указатели. Ну так и пишите все в терминах указателей. Никаких "rvalue ссылок" тут и в помине быть не должно.

В-четвертых, как вам уже сказали не раз, как бы вы это все ни реализовывали, если ваш контейнер хранит указатели, то обеспечивать правильное время время жизни объектов, на которые указывают ваши указатели - ваша обязанность. В том коде, который вы привели, вы пытаетесь хранить указатели на временные объекты, т.е на объекты, которые уничтожаются сразу же после создания, оставляя за собой "мертвые" указатели. Вот эти "мертвые" указатели вы и пытаетесь хранить. Это бессмысленно и неработоспособно. И никакое "присваивание значения rvalue ссылки" это не исправит.
1
0 / 0 / 0
Регистрация: 14.05.2020
Сообщений: 50
08.05.2021, 18:12  [ТС] 14
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Но при чем здесь вообще какие-то "rvalue ссылки"?
Я понял свою ошибку. Просто решил поэкспериментировать и понять, что же такое rvalue ссылки, однако эксперимент неудачный. Не до конца приходит понимание rvalue ссылок, как они работают, и когда стоит их применять,а когда нет. Есть ли какой-нибудь хороший источник, где можно изучить эту тему? Искал, что-то уже читал, но как-то все равно не укладывается в голове
0
16495 / 8988 / 2205
Регистрация: 30.01.2014
Сообщений: 15,603
08.05.2021, 19:19 15
Цитата Сообщение от newmersedez Посмотреть сообщение
Есть ли какой-нибудь хороший источник, где можно изучить эту тему?
http://www.williamspublishing.... 000-3.html
1
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
08.05.2021, 19:19
Помогаю со студенческими работами здесь

Создайте шаблонный класс односвязного списка. C++
Требуется создать реализации для типичных операций над элементами: - AddToHead – добавление...

как переделать шаблонный класс-стек в шаблонный класс-очередь !
Есть класс-контейнер стек с сортировкой , а нужно класс-контейнер очередь ! как переделать ??...

Создать шаблонный класс библиотека на основе односвязного списка
мне нужно создать класс библиотека на основе односвязного списка, но список должен быть шаблонным,...

Динамический класс на основе двусвязного списка(перевод кода с Java на С++)
Логика задачи: Создать динамический класс Route на основе двусвязного списка, где каждый элемент...

Зачем нужны rvalue ссылки, если есть универсальные ссылки
Читаю книгу Скотта Мэйерса... Что-то я совсем запутался с этими rvalue ссылками. Я не пойму, зачем...

Шаблонный класс: упорядоченный стек на основе связного списка в динамической памяти
Создать шаблонный класс - упорядоченный стек на основе связного списка в динамической памяти. Тип...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
15
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2023, CyberForum.ru