С Новым годом! Форум программистов, компьютерный форум, киберфорум
C++
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.76/21: Рейтинг темы: голосов - 21, средняя оценка - 4.76
 Аватар для spoilsport
1 / 1 / 0
Регистрация: 17.08.2020
Сообщений: 19

Дек (deque) - проверка знаний

03.08.2021, 13:42. Показов 4449. Ответов 27

Студворк — интернет-сервис помощи студентам
Добрый день/вечер/ночь.

Захотел воспользоваться знаниями опытных программистов этого форума и получить критику по ниже представленному "коду"

Очень интересны абсолютно любые замечания, касающиеся стиля (если он там есть), работой с памятью и изобретенных велосипедов. Понимаю, что снизу представлен слишком скудноватый на строки код, чтобы по нему делать какие-то выводы, но уверен, что даже в нем находятся ошибки, которых я не замечаю ввиду своей неопытности.

Итак, ниже я попытался написать дек при помощи динамического массива. Акцентирую внимание, что просматривал как работает стандартная библиотека <deque>, чтобы не отходить от её функционала. И немного глупо (по-моему мнению) получились методы begin() И end(), так как для очереди может быть выделена память из кучи, но заполнена только до половины, однако метод end() вернет значение на последний "мусорный" элемент очереди. Посмотрел и в <deque> работает это точно также, однако возможно чего то не заметил или не понял.

Здесь ссылка на GitHub, если понадобится: https://github.com/spo1lsp0rt/deque_darr

Ниже также находится вывод в консоль.

Заранее благодарю за потраченное вами время
Код:
Кликните здесь для просмотра всего текста

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
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
/*
 Ниже представлен программный код реализации дека на базе динамического массива.
 Удалось реализовать методы:
 assign, front, back, size, empty, begin, end, insert(pos,val),
 push_front, push_back, pop_front, pop_back, clear
*/
#include <iostream>
 
template <typename T>
class deque
{
private:
    T *a;
    unsigned int d_size;
 
public:
    deque(const unsigned int& _size, const T& val) {
        a = new T[_size];
        for (unsigned int i = 0; i < _size; i++) {
            a[i] = val;
        }
        d_size = _size;
    }
    deque(const unsigned int& _size) {
        a = new T[_size];
        for (unsigned int i = 0; i < _size; i++) {
            a[i] = NULL;
        }
        d_size = _size;
    }
 
    void assign(const unsigned int& _size, const T& val) {
        if (d_size != 0) delete a;
        a = new T[_size];
        for (unsigned int i = 0; i < _size; i++) {
            a[i] = val;
        }
        d_size = _size;
    }
 
    T& front() {
        return a[0];
    }
 
    T& back() {
        return a[d_size - 1];
    }
 
    unsigned int size() {
        return d_size;
    }
 
    bool empty() {
        return d_size == 0;
    }
 
    unsigned int begin() const {
        return 0;
    }
 
    unsigned int end() const {
        return d_size - 1;
    }
 
    void insert(const unsigned int& pos, const T& val) {
        if (d_size == 0) {
            d_size++;
            a = new T[d_size];
            a[0] = val;
        }
        else {
            d_size++;
            T* temp = new T[d_size];
            for (unsigned int i = 0; i < pos; i++) {
                temp[i] = a[i];
            }
            temp[pos] = val;
            for (unsigned int i = pos; i < d_size - 1; i++) {
                temp[i + 1] = a[i];
            }
            delete a;
            a = new T[d_size];
            for (unsigned int i = 0; i < d_size; i++) {
                a[i] = temp[i];
            }
            delete temp;
        }
    }
 
    void push_front(const T& val) {
        if (d_size == 0) {
            d_size++;
            a = new T[d_size];
            a[0] = val;
        }
        else {
            d_size++;
            T* temp = new T[d_size];
            temp[0] = val;
            for (unsigned int i = 0; i < d_size - 1; i++) {
                temp[i + 1] = a[i];
            }
            delete a;
            a = new T[d_size];
            for (unsigned int i = 0; i < d_size; i++) {
                a[i] = temp[i];
            }
            delete temp;
        }
    }
 
    void push_back(const T& val) {
        if (d_size == 0) {
            d_size++;
            a = new T[d_size];
            a[0] = val;
        }
        else {
            d_size++;
            T* temp = new T[d_size];
            for (unsigned int i = 0; i < d_size - 1; i++) {
                temp[i] = a[i];
            }
            delete a;
            a = new T[d_size];
            for (unsigned int i = 0; i < d_size; i++) {
                a[i] = temp[i];
            }
            delete temp;
            a[d_size - 1] = val;
        }
    }
 
    void pop_front() {
        if (d_size == 0) {
            throw std::out_of_range("err: out of range");
        }
        else {
            d_size--;
            T* temp = new T[d_size];
            for (unsigned int i = 0; i < d_size; i++) {
                temp[i] = a[i + 1];
            }
            delete a;
            a = new T[d_size];
            for (unsigned int i = 0; i < d_size; i++) {
                a[i] = temp[i];
            }
            delete temp;
        }
    }
 
    void pop_back() {
        if (d_size == 0) {
            throw std::out_of_range("err: out of range");
        }
        else {
            d_size--;
            T* temp = new T[d_size];
            for (int i = d_size - 1; i >= 0; i--) {
                temp[i] = a[i];
            }
            delete a;
            a = new T[d_size];
            for (unsigned int i = 0; i < d_size; i++) {
                a[i] = temp[i];
            }
            delete temp;
        }
    }
 
    void clear() {
        delete a;
        d_size = 0;
    }
 
    T& operator[](const unsigned int& pos) {
        if (pos >= d_size) {
            throw std::out_of_range("err: out of range");
        }
        else return a[pos];
    }
};
 
using namespace std;
 
int main()
{
    setlocale(LC_ALL, "ru");
    deque<int> dq(3, 1);
    //изменили первое значение дека вызовом front()
    dq.front() = 777;
    //изменили промежуточное значение дека вызовом оператора []
    dq[1] = 888;
    //изменили последнее значение дека вызовом back()
    dq.back() = 999;
    cout << "Первое значение дека: " << dq.front() << endl;
    cout << "Промежуточное значение дека: " << dq[1] << endl;
    cout << "Последнее значение дека: " << dq.back() << endl;
 
    cout << "Пуст ли дек? Ответ: " << dq.empty() << endl;
    dq.clear();
    cout << "Очистили дек. Пуст ли дек? Ответ: " << dq.empty() << endl;
 
    dq.assign(5, 9);
    cout << "Воспользовались assign(). \nВывод дека:  ";
    for (size_t i = dq.begin(); i <= dq.end(); i++) {
        cout << dq[i] << " ";
    }
    cout << endl << "Размер дека: " << dq.size() << endl;
    dq.insert(dq.begin(), 0);
    cout << endl << "Воспользовались insert() для begin(). \nВывод дека:  ";
    for (size_t i = dq.begin(); i <= dq.end(); i++) {
        cout << dq[i] << " ";
    }
    dq.pop_back();
    dq.pop_front();
    cout << endl << "Воспользовались pop_back() и pop_front(). \nВывод дека:  ";
    for (size_t i = dq.begin(); i <= dq.end(); i++) {
        cout << dq[i] << " ";
    }
    dq.push_back(-5);
    dq.push_front(-5);
    cout << endl << "Воспользовались push_back() и push_front(). \nВывод дека:  ";
    for (size_t i = dq.begin(); i <= dq.end(); i++) {
        cout << dq[i] << " ";
    }
    cout << endl;
    return 0;
}

Вывод в консоли:
Кликните здесь для просмотра всего текста

Первое значение дека: 777
Промежуточное значение дека: 888
Последнее значение дека: 999
Пуст ли дек? Ответ: 0
Очистили дек. Пуст ли дек? Ответ: 1
Воспользовались assign().
Вывод дека: 9 9 9 9 9
Размер дека: 5

Воспользовались insert() для begin().
Вывод дека: 0 9 9 9 9 9
Воспользовались pop_back() и pop_front().
Вывод дека: 9 9 9 9
Воспользовались push_back() и push_front().
Вывод дека: -5 9 9 9 9 -5
0
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
03.08.2021, 13:42
Ответы с готовыми решениями:

Deque (Дек) на двусвязном списке
Стояла задача реализовать дек с указателем только на начало очереди. Мой код вроде как рабочий, но хотелось бы поинтересоваться с более...

Создание ДЕК (как стэк только о двух концах) без <deque>
здравствуйте! написал класс Deque, создал методы push_back(), push_front(), pop_back(), pop_front()... Все работает нормально, кроме...

Есть ли в Qt контейнер типа "Дек" (deque) или надо свой написать?
Пока не нашёл. Если нет, то от кого лучше унаследоваться, чтобы реализовать?

27
Эксперт С++
 Аватар для hoggy
8973 / 4319 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
03.08.2021, 14:48
Цитата Сообщение от spoilsport Посмотреть сообщение
получить критику по ниже представленному "коду"
прежде чем выкладывать код на ревью,
его нужно сначала проверить.
исправить все явные ошибки, недочеты, а так же косяки,
о которых тебе сообщает компилятор
и только потом выкладывать на code-review.


сейчас рассматривать твой код нет никакого смысла.
вот когда ты исправишь все явные косяки,
вот тогда и приходи.
0
 Аватар для spoilsport
1 / 1 / 0
Регистрация: 17.08.2020
Сообщений: 19
03.08.2021, 15:06  [ТС]
Здравствуйте.
Если я правильно понял, то Вы имели ввиду предупреждения. Неправильно очищал память от данных. Однако в остальном код работает исправно. Исправления прикрепил ниже.
Кликните здесь для просмотра всего текста

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
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
/*
 Ниже представлена программный код реализации дека на базе динамического массива.
 Удалось реализовать методы:
 assign, front, back, size, empty, begin, end, insert(pos,val),
 push_front, push_back, pop_front, pop_back, clear
*/
#include <iostream>
 
template <typename T>
class deque
{
private:
    T *a;
    unsigned int d_size;
 
public:
    deque(const unsigned int& _size, const T& val) {
        a = new T[_size];
        for (unsigned int i = 0; i < _size; i++) {
            a[i] = val;
        }
        d_size = _size;
    }
    deque(const unsigned int& _size) {
        a = new T[_size];
        for (unsigned int i = 0; i < _size; i++) {
            a[i] = NULL;
        }
        d_size = _size;
    }
 
    void assign(const unsigned int& _size, const T& val) {
        if (d_size != 0) delete a;
        a = new T[_size];
        for (unsigned int i = 0; i < _size; i++) {
            a[i] = val;
        }
        d_size = _size;
    }
 
    T& front() {
        return a[0];
    }
 
    T& back() {
        return a[d_size - 1];
    }
 
    unsigned int size() {
        return d_size;
    }
 
    bool empty() {
        return d_size == 0;
    }
 
    unsigned int begin() const {
        return 0;
    }
 
    unsigned int end() const {
        return d_size - 1;
    }
 
    void insert(const unsigned int& pos, const T& val) {
        if (d_size == 0) {
            d_size++;
            a = new T[d_size];
            a[0] = val;
        }
        else {
            d_size++;
            T* temp = new T[d_size];
            for (unsigned int i = 0; i < pos; i++) {
                temp[i] = a[i];
            }
            temp[pos] = val;
            for (unsigned int i = pos; i < d_size - 1; i++) {
                temp[i + 1] = a[i];
            }
            delete[] a;
            a = new T[d_size];
            for (unsigned int i = 0; i < d_size; i++) {
                a[i] = temp[i];
            }
            delete[] temp;
        }
    }
 
    void push_front(const T& val) {
        if (d_size == 0) {
            d_size++;
            a = new T[d_size];
            a[0] = val;
        }
        else {
            d_size++;
            T* temp = new T[d_size];
            temp[0] = val;
            for (unsigned int i = 0; i < d_size - 1; i++) {
                temp[i + 1] = a[i];
            }
            delete[] a;
            a = new T[d_size];
            for (unsigned int i = 0; i < d_size; i++) {
                a[i] = temp[i];
            }
            delete[] temp;
        }
    }
 
    void push_back(const T& val) {
        if (d_size == 0) {
            d_size++;
            a = new T[d_size];
            a[0] = val;
        }
        else {
            d_size++;
            T* temp = new T[d_size];
            for (unsigned int i = 0; i < d_size - 1; i++) {
                temp[i] = a[i];
            }
            delete[] a;
            a = new T[d_size];
            for (unsigned int i = 0; i < d_size; i++) {
                a[i] = temp[i];
            }
            delete[] temp;
            a[d_size - 1] = val;
        }
    }
 
    void pop_front() {
        if (d_size == 0) {
            throw std::out_of_range("err: out of range");
        }
        else {
            d_size--;
            T* temp = new T[d_size];
            for (unsigned int i = 0; i < d_size; i++) {
                temp[i] = a[i + 1];
            }
            delete[] a;
            a = new T[d_size];
            for (unsigned int i = 0; i < d_size; i++) {
                a[i] = temp[i];
            }
            delete[] temp;
        }
    }
 
    void pop_back() {
        if (d_size == 0) {
            throw std::out_of_range("err: out of range");
        }
        else {
            d_size--;
            T* temp = new T[d_size];
            for (int i = d_size - 1; i >= 0; i--) {
                temp[i] = a[i];
            }
            delete[] a;
            a = new T[d_size];
            for (unsigned int i = 0; i < d_size; i++) {
                a[i] = temp[i];
            }
            delete[] temp;
        }
    }
 
    void clear() {
        delete[] a;
        d_size = 0;
    }
 
    T& operator[](const unsigned int& pos) {
        if (pos >= d_size) {
            throw std::out_of_range("err: out of range");
        }
        else return a[pos];
    }
};
 
using namespace std;
 
int main()
{
    setlocale(LC_ALL, "ru");
    deque<int> dq(3, 1);
    //изменили первое значение дека вызовом front()
    dq.front() = 777;
    //изменили промежуточное значение дека вызовом оператора []
    dq[1] = 888;
    //изменили последнее значение дека вызовом back()
    dq.back() = 999;
    cout << "Первое значение дека: " << dq.front() << endl;
    cout << "Промежуточное значение дека: " << dq[1] << endl;
    cout << "Последнее значение дека: " << dq.back() << endl;
 
    cout << "Пуст ли дек? Ответ: " << dq.empty() << endl;
    dq.clear();
    cout << "Очистили дек. Пуст ли дек? Ответ: " << dq.empty() << endl;
 
    dq.assign(5, 9);
    cout << "Воспользовались assign(). \nВывод дека:  ";
    for (size_t i = dq.begin(); i <= dq.end(); i++) {
        cout << dq[i] << " ";
    }
    cout << endl << "Размер дека: " << dq.size() << endl;
    dq.insert(dq.begin(), 0);
    cout << endl << "Воспользовались insert() для begin(). \nВывод дека:  ";
    for (size_t i = dq.begin(); i <= dq.end(); i++) {
        cout << dq[i] << " ";
    }
    dq.pop_back();
    dq.pop_front();
    cout << endl << "Воспользовались pop_back() и pop_front(). \nВывод дека:  ";
    for (size_t i = dq.begin(); i <= dq.end(); i++) {
        cout << dq[i] << " ";
    }
    dq.push_back(-5);
    dq.push_front(-5);
    cout << endl << "Воспользовались push_back() и push_front(). \nВывод дека:  ";
    for (size_t i = dq.begin(); i <= dq.end(); i++) {
        cout << dq[i] << " ";
    }
    cout << endl;
    return 0;
}
0
фрилансер
 Аватар для Алексей1153
6449 / 5643 / 1129
Регистрация: 11.10.2019
Сообщений: 15,025
03.08.2021, 15:11
spoilsport, по меньшей мере: конструктор по умолчанию, деструктор (освобождать память то надо?), использован unsigned int вместо size_t

Добавлено через 46 секунд
NULL -> nullptr
0
Эксперт С++
 Аватар для hoggy
8973 / 4319 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
03.08.2021, 15:44
Цитата Сообщение от spoilsport Посмотреть сообщение
Исправления прикрепил ниже.
ты не исправил ворнинги
0
 Аватар для spoilsport
1 / 1 / 0
Регистрация: 17.08.2020
Сообщений: 19
03.08.2021, 15:51  [ТС]
hoggy, Cпасибо за такой полезный сайт Дело в том, что я пользуюсь лишь информацией, которую выдает мне мой компилятор и такого количества как у Вас - у меня не было. Сейчас просмотрю все и подправлю.

Добавлено через 3 минуты
Алексей1153,
Цитата Сообщение от Алексей1153 Посмотреть сообщение
по меньшей мере: конструктор по умолчанию, деструктор (освобождать память то надо?)
Спасибо за замечание. Не удобно вышло с деструктором

Цитата Сообщение от Алексей1153 Посмотреть сообщение
использован unsigned int вместо size_t
unsigned int не использовал больше не по неопытности, а по глупости
0
Эксперт С++
 Аватар для hoggy
8973 / 4319 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
03.08.2021, 16:14
Цитата Сообщение от spoilsport Посмотреть сообщение
Cпасибо за такой полезный сайт Дело в том, что я пользуюсь лишь информацией, которую выдает мне мой компилятор и такого количества как у Вас - у меня не было.
это потому, что ты не настроил свой компилятор.

у компиляторов есть такое понятие: "уровень предупреждений".
чем он выше, тем больше всяких косяков показывает компилятор.
на максимальных уровнях компиляторы начинают докалебываться до каждой запятой.
и именно такой уровень используют люди, которые хотят получить качественный код.

как именно настраивается твой компилятор, описано в его документации.
я не знаю какой у тебя компилятор, но если у тебя, например, компилятор Visual Studio,
то почитать можно здесь.


мой опыт показывает:
что бы гарантировать высокое качество кода,
недостаточно протестировать его только на одном компиляторе.

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

и если хотя бы один компилятор покажет хотя бы один ворнинг - код отправится на доработку.
если хотя бы одна сборка зафейлит хотя бы один юнит-тест - код отправится на доработку.

мой опыт показывает: редко когда код сразу получается качественным.
обычно на практике он по многу раз отправляется на доработку.
1
 Аватар для spoilsport
1 / 1 / 0
Регистрация: 17.08.2020
Сообщений: 19
03.08.2021, 17:34  [ТС]
hoggy, спасибо большое, мне это поможет в будущем. Нашел как настроить "уровень предупреждений" в VS, классно, что теперь знаю о такой функции.
Исправил код, предупреждений больше не выдает, кроме совета об использовании списка инициализации для одного из конструкторов. Но я не могу переписать конструктор под такой механизм, потому что нужно использование цикла.
Понимаю, что это не то, что нужно отправлять на кодревью. Необходимо просто практиковаться больше, но я надеялся подчеркнуть ошибки уже на этой стадии. И я уже узнал много чего интересного из этой темы
Поэтому если у Вас будет свободное время, посмотрите пожалуйста мой бедо-код.
Кликните здесь для просмотра всего текста

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
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
/*
 Ниже представлена программный код реализации дека на базе динамического массива.
 Удалось реализовать методы:
 assign, front, back, size, empty, begin, end, insert(pos,val),
 push_front, push_back, pop_front, pop_back, clear
*/
#include <iostream>
 
template <typename T>
class deque
{
private:
    T *a;
    size_t d_size;
 
public:
    deque() : d_size(0), a() {}
    deque(const deque<T>& _deque) {
        this = _deque;
    }
    deque(const size_t& _size, const T& val) {
        a = new T[_size];
        for (size_t i = 0; i < _size; i++) {
            a[i] = val;
        }
        d_size = _size;
    }
    deque(const size_t& _size) {
        a = new T[_size];
        for (size_t i = 0; i < _size; i++) {
            a[i] = 0;
        }
        d_size = _size;
    }
    ~deque() {
        if (d_size) {
            delete[] a;
        }
    }
 
    void assign(const size_t& _size, const T& val) {
        if (d_size) delete[] a;
        a = new T[_size];
        for (size_t i = 0; i < _size; i++) {
            a[i] = val;
        }
        d_size = _size;
    }
 
    T& front() {
        return a[0];
    }
 
    T& back() {
        return a[d_size - 1];
    }
 
    size_t size() {
        return d_size;
    }
 
    bool empty() {
        return d_size == 0;
    }
 
    size_t begin() const {
        return 0;
    }
 
    size_t end() const {
        if (d_size) return d_size - 1;
        return 0;
    }
 
    void insert(const size_t& pos, const T& val) {
        if (d_size == 0) {
            d_size++;
            a = new T[d_size];
            a[0] = val;
        }
        else {
            d_size++;
            T* temp = new T[d_size];
            for (size_t i = 0; i < pos; i++) {
                temp[i] = a[i];
            }
            temp[pos] = val;
            for (size_t i = pos; i < d_size - 1; i++) {
                temp[i + 1] = a[i];
            }
            delete[] a;
            a = new T[d_size];
            for (size_t i = 0; i < d_size; i++) {
                a[i] = temp[i];
            }
            delete[] temp;
        }
    }
 
    void push_front(const T& val) {
        if (d_size == 0) {
            d_size++;
            a = new T[d_size];
            a[0] = val;
        }
        else {
            d_size++;
            T* temp = new T[d_size];
            temp[0] = val;
            for (size_t i = 0; i < d_size - 1; i++) {
                temp[i + 1] = a[i];
            }
            delete[] a;
            a = new T[d_size];
            for (size_t i = 0; i < d_size; i++) {
                a[i] = temp[i];
            }
            delete[] temp;
        }
    }
 
    void push_back(const T& val) {
        if (d_size == 0) {
            d_size++;
            a = new T[d_size];
            a[0] = val;
        }
        else {
            d_size++;
            T* temp = new T[d_size];
            for (size_t i = 0; i < d_size - 1; i++) {
                temp[i] = a[i];
            }
            delete[] a;
            a = new T[d_size];
            for (size_t i = 0; i < d_size; i++) {
                a[i] = temp[i];
            }
            delete[] temp;
            a[d_size - 1] = val;
        }
    }
 
    void pop_front() {
        if (d_size == 0) {
            throw std::out_of_range("err: out of range");
        }
        else {
            d_size--;
            T* temp = new T[d_size];
            for (size_t i = 0; i < d_size; i++) {
                temp[i] = a[i + 1];
            }
            delete[] a;
            a = new T[d_size];
            for (size_t i = 0; i < d_size; i++) {
                a[i] = temp[i];
            }
            delete[] temp;
        }
    }
 
    void pop_back() {
        if (d_size == 0) {
            throw std::out_of_range("err: out of range");
        }
        else {
            d_size--;
            T* temp = new T[d_size];
            for (size_t i = 0; i < d_size; i++) {
                temp[i] = a[i];
            }
            delete[] a;
            a = new T[d_size];
            for (size_t i = 0; i < d_size; i++) {
                a[i] = temp[i];
            }
            delete[] temp;
        }
    }
 
    void clear() {
        delete[] a;
        d_size = 0;
    }
 
    T& operator=(const deque<T>& _deque) {
        if (d_size != 0) delete[] a;
        d_size = _deque.d_size;
        a = new T[d_size];
        for (size_t i = 0; i < d_size; i++) {
            a[i] = _deque[i];
        }
    }
 
    T& operator[](const size_t& pos) {
        if (pos >= d_size) {
            throw std::out_of_range("err: out of range");
        }
        else return a[pos];
    }
};
 
using namespace std;
 
int main()
{
    setlocale(LC_ALL, "ru");
    deque<int> dq(3);
    for (size_t i = dq.begin(); i <= dq.end(); i++) {
        cout << dq[i] << " ";
    }
    cout << endl;
    //изменили первое значение дека вызовом front()
    dq.front() = 777;
    //изменили промежуточное значение дека вызовом оператора []
    dq[1] = 888;
    //изменили последнее значение дека вызовом back()
    dq.back() = 999;
    cout << "Первое значение дека: " << dq.front() << endl;
    cout << "Промежуточное значение дека: " << dq[1] << endl;
    cout << "Последнее значение дека: " << dq.back() << endl;
 
    cout << "Пуст ли дек? Ответ: " << dq.empty() << endl;
    dq.clear();
    cout << "Очистили дек. Пуст ли дек? Ответ: " << dq.empty() << endl;
 
    dq.assign(5, 9);
    cout << "Воспользовались assign(). \nВывод дека:  ";
    for (size_t i = dq.begin(); i <= dq.end(); i++) {
        cout << dq[i] << " ";
    }
    cout << endl << "Размер дека: " << dq.size() << endl;
    dq.insert(dq.begin(), 0);
    cout << endl << "Воспользовались insert() для begin(). \nВывод дека:  ";
    for (size_t i = dq.begin(); i <= dq.end(); i++) {
        cout << dq[i] << " ";
    }
    dq.pop_back();
    dq.pop_front();
    cout << endl << "Воспользовались pop_back() и pop_front(). \nВывод дека:  ";
    for (size_t i = dq.begin(); i <= dq.end(); i++) {
        cout << dq[i] << " ";
    }
    dq.push_back(-5);
    dq.push_front(-5);
    cout << endl << "Воспользовались push_back() и push_front(). \nВывод дека:  ";
    for (size_t i = dq.begin(); i <= dq.end(); i++) {
        cout << dq[i] << " ";
    }
    cout << endl;
    return 0;
}
0
фрилансер
 Аватар для Алексей1153
6449 / 5643 / 1129
Регистрация: 11.10.2019
Сообщений: 15,025
03.08.2021, 18:01
Цитата Сообщение от spoilsport Посмотреть сообщение
this = _deque;
разыменование this пропущено

Цитата Сообщение от spoilsport Посмотреть сообщение
T& operator=(const deque<T>& _deque) {
        if (d_size != 0) delete[] a;
проверка на копирование самого себя пропущена

Цитата Сообщение от spoilsport Посмотреть сообщение
потому что нужно использование цикла
для списка инициализации цикл не нужен
там имеется в виду инициализация полей
deque(const size_t& _size) :d_size{}, a{} {

ну и ещё обращается внимание на порядок инициализации - он должен соответствовать порядку полей в классе

а вообще, лучше прямо в месте объявления полей в классе инициализацию задать
C++
1
2
3
4
5
6
template <typename T>
class deque
{
private:
    T *a{};
    size_t d_size{};
1
Неэпический
 Аватар для Croessmah
18144 / 10728 / 2066
Регистрация: 27.09.2012
Сообщений: 27,026
Записей в блоге: 1
03.08.2021, 18:14
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
    void push_front(const T& val) {
        if (d_size == 0) {
            d_size++;
            a = new T[d_size];
            a[0] = val;
        }
        else {
            d_size++;
            T* temp = new T[d_size];
            temp[0] = val;
            for (size_t i = 0; i < d_size - 1; i++) {
                temp[i + 1] = a[i];
            }
            delete[] a;
 
            //Зачем это выделение памяти и цикл?
            //просто a = temp и всё
            a = new T[d_size]; 
            for (size_t i = 0; i < d_size; i++) {
                a[i] = temp[i];
            }
            delete[] temp;
        }
    }
Добавлено через 4 минуты
C++
1
2
3
4
5
6
7
8
    T& operator=(const deque<T>& _deque) {
        if (d_size != 0) delete[] a;
        d_size = _deque.d_size;
        a = new T[d_size];
        for (size_t i = 0; i < d_size; i++) {
            a[i] = _deque[i];
        }
    }
Если _deque.d_size окажется равным нулю, то в результате будет течь память,
т.к. везде перед delete [] a идут проверки именно по d_size.
1
 Аватар для spoilsport
1 / 1 / 0
Регистрация: 17.08.2020
Сообщений: 19
03.08.2021, 20:24  [ТС]
Алексей1153,
Цитата Сообщение от Алексей1153 Посмотреть сообщение
разыменование this пропущено
спасибо, знаю ведь и понимаю, что это нужно, но почему то упустил

Цитата Сообщение от Алексей1153 Посмотреть сообщение
проверка на копирование самого себя пропущена
точно, нужно будет добавить

Цитата Сообщение от Алексей1153 Посмотреть сообщение
для списка инициализации цикл не нужен
там имеется в виду инициализация полей
deque(const size_t& _size) :d_size{}, a{} {
да, я понимаю. написав про цикл я имел ввиду присваивание деку поэлементно значений. вот в этом моменте:
Кликните здесь для просмотра всего текста

C++
1
2
3
4
5
6
7
deque(const size_t& _size) {
        a = new T[_size];
        for (size_t i = 0; i < _size; i++) { <--- вот тут
            a[i] = 0;
        }
        d_size = _size;
    }


Цитата Сообщение от Алексей1153 Посмотреть сообщение
ну и ещё обращается внимание на порядок инициализации - он должен соответствовать порядку полей в классе
понял, запомню это. еще не так часто пользовался этим механизмом, не знал.

Цитата Сообщение от Алексей1153 Посмотреть сообщение
а вообще, лучше прямо в месте объявления полей в классе инициализацию задать
это очень круто. спасибо большое. решилась проблема с предупреждением, которое выдавал компилятор:
Кликните здесь для просмотра всего текста

Code
1
2
3
4
5
6
7
Warning(s):
986356637/source.cpp: In instantiation of ‘deque<T>::deque(const size_t&) [with T = int; size_t = long unsigned int]’:
986356637/source.cpp:209:20:   required from here
986356637/source.cpp:28:5: warning: ‘deque<int>::a’ should be initialized in the member initialization list [-Weffc++]
     deque(const size_t& _size) {
     ^~~~~
986356637/source.cpp:28:5: warning: ‘deque<int>::d_size’ should be initialized in the member initialization list [-Weffc++]


Добавлено через 19 минут
Цитата Сообщение от Croessmah Посмотреть сообщение
//Зачем это выделение памяти и цикл?
            //просто a = temp и всё
            a = new T[d_size];
            for (size_t i = 0; i < d_size; i++) {
                a[i] = temp[i];
            }
            delete[] temp;
Я делал таким образом. Поправьте, если я не прав. Насколько я понимаю при использовании конструкции ниже происходит копирование данных из указателя p2 в указатель p1. И после же удаления указателя p2 его данные, которые мы копировали, остаются не стертыми:
Кликните здесь для просмотра всего текста

C++
1
2
3
4
5
int* p1;
int* p2;
p2 = 5;
p1 = p2;
delete p2;

Когда же мы пишем как ниже, происходит именно передача адреса второго указателя в ячейку памяти первого указателя. И в таком случае, после удаления p2 указателя происходит разрыв связи первого указателя p1 со вторым p2.
Кликните здесь для просмотра всего текста

C++
1
2
3
4
5
int* p1;
int* p2;
p2 = 5;
p1 = &p2;
delete p2;

Но когда я делал, как указали Вы, происходило так же как и во втором случае. Хотя казалось бы (как я понимаю) при a = temp создается копия temp'a и присваивается деку a.
Вот я и встал в ступор. При очистке памяти временного temp дека почему то очищалась память и для основного дека. Когда же я убрал очистку временного дека delete[] temp, в основном деке оставались значения временного. Но я не понял почему, ведь по сути область видимости временного temp дека заканчивается при выходе из метода и он все равно очищается (поправьте, пожалуйста, если я косячник и не прав). Мне не понравилась вся эта ситуация, и поэтому я решил на время сделать именно ту запись, которую Вы видели.

Цитата Сообщение от Croessmah Посмотреть сообщение
Если _deque.d_size окажется равным нулю, то в результате будет течь память,
т.к. везде перед delete [] a идут проверки именно по d_size.
Получается нужно еще поставить проверку для размера r-value дека. Спасибо большое, исправлю

Добавлено через 22 минуты

Добавлено через 19 минут
Исправил все замечания выше. Еще раз благодарю за такую помощь, думаю мне это действительно помогает
Кликните здесь для просмотра всего текста

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
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
/*
 Дек(deque) — это сокращенная фраза «double - ended - queue», что, в переводе с английского, означает — двусторонняя очередь.
 Контейнер Дек очень похож на контейнер — Вектор, также как и Вектора, Деки являются динамическими массивами.
 Разница между Вектором и Деком состоит лишь в том, что в деках динамический массив открыт с двух сторон.
 Это и позволяет очень быстро добавлять новые элементы как в конец так и в начало контейнера.
 
 Ниже представлена программный код реализации дека на базе динамического массива.
 Удалось реализовать методы:
 assign, front, back, size, empty, begin, end, insert(pos,val),
 push_front, push_back, pop_front, pop_back, clear
*/
#include <iostream>
 
template <typename T>
class deque
{
private:
    T* a{};
    size_t d_size{};
 
public:
    deque() : d_size(0), a() {}
    deque(const deque<T>& _deque) {
        *this = _deque;
    }
    deque(const size_t& _size, const T& val) {
        a = new T[_size];
        for (size_t i = 0; i < _size; i++) {
            a[i] = val;
        }
        d_size = _size;
    }
    deque(const size_t& _size) {
        a = new T[_size];
        for (size_t i = 0; i < _size; i++) {
            a[i] = 0;
        }
        d_size = _size;
    }
    ~deque() {
        if (d_size) {
            delete[] a;
        }
    }
 
    void assign(const size_t& _size, const T& val) {
        if (d_size) delete[] a;
        a = new T[_size];
        for (size_t i = 0; i < _size; i++) {
            a[i] = val;
        }
        d_size = _size;
    }
 
    T& front() {
        return a[0];
    }
 
    T& back() {
        return a[d_size - 1];
    }
 
    size_t size() {
        return d_size;
    }
 
    bool empty() {
        return d_size == 0;
    }
 
    size_t begin() const {
        return 0;
    }
 
    size_t end() const {
        if (d_size) return d_size - 1;
        return 0;
    }
 
    void insert(const size_t& pos, const T& val) {
        if (d_size == 0) {
            d_size++;
            a = new T[d_size];
            a[0] = val;
        }
        else {
            d_size++;
            T* temp = new T[d_size];
            for (size_t i = 0; i < pos; i++) {
                temp[i] = a[i];
            }
            temp[pos] = val;
            for (size_t i = pos; i < d_size - 1; i++) {
                temp[i + 1] = a[i];
            }
            delete[] a;
            a = new T[d_size];
            for (size_t i = 0; i < d_size; i++) {
                a[i] = temp[i];
            }
            delete[] temp;
        }
    }
 
    void push_front(const T& val) {
        if (d_size == 0) {
            d_size++;
            a = new T[d_size];
            a[0] = val;
        }
        else {
            d_size++;
            T* temp = new T[d_size];
            temp[0] = val;
            for (size_t i = 0; i < d_size - 1; i++) {
                temp[i + 1] = a[i];
            }
            delete[] a;
            a = new T[d_size];
            for (size_t i = 0; i < d_size; i++) {
                a[i] = temp[i];
            }
            delete[] temp;
        }
    }
 
    void push_back(const T& val) {
        if (d_size == 0) {
            d_size++;
            a = new T[d_size];
            a[0] = val;
        }
        else {
            d_size++;
            T* temp = new T[d_size];
            for (size_t i = 0; i < d_size - 1; i++) {
                temp[i] = a[i];
            }
            delete[] a;
            a = new T[d_size];
            for (size_t i = 0; i < d_size; i++) {
                a[i] = temp[i];
            }
            delete[] temp;
            a[d_size - 1] = val;
        }
    }
 
    void pop_front() {
        if (d_size == 0) {
            throw std::out_of_range("err: out of range");
        }
        else {
            d_size--;
            T* temp = new T[d_size];
            for (size_t i = 0; i < d_size; i++) {
                temp[i] = a[i + 1];
            }
            delete[] a;
            a = new T[d_size];
            for (size_t i = 0; i < d_size; i++) {
                a[i] = temp[i];
            }
            delete[] temp;
        }
    }
 
    void pop_back() {
        if (d_size == 0) {
            throw std::out_of_range("err: out of range");
        }
        else {
            d_size--;
            T* temp = new T[d_size];
            for (size_t i = 0; i < d_size; i++) {
                temp[i] = a[i];
            }
            delete[] a;
            a = new T[d_size];
            for (size_t i = 0; i < d_size; i++) {
                a[i] = temp[i];
            }
            delete[] temp;
        }
    }
 
    void clear() {
        delete[] a;
        d_size = 0;
    }
 
    bool operator==(const deque<T>& _deque) {
        if (d_size != _deque.d_size) return false;
        else {
            for (size_t i = 0; i < d_size; i++) {
                if (a[i] != _deque.a[i]) return false;
            }
        }
        return true;
    }
 
    deque<T>& operator=(const deque<T>& _deque) {
        if (!(*this == _deque) && !(_deque.d_size == 0)) {
            if (d_size != 0) delete[] a;
            d_size = _deque.d_size;
            a = new T[d_size];
            for (size_t i = 0; i < d_size; i++) {
                a[i] = _deque.a[i];
            }
        }
        return *this;
    }
 
    T& operator[](const size_t& pos) {
        if (pos >= d_size) {
            throw std::out_of_range("err: out of range");
        }
        else return a[pos];
    }
};
 
using namespace std;
 
int main()
{
    setlocale(LC_ALL, "ru");
    deque<int> dq(3, 1);
    for (size_t i = dq.begin(); i <= dq.end(); i++) {
        cout << dq[i] << " ";
    }
    //при присваивании самого себя срабатывает проверка, данные не потеряются
    dq = dq;
    cout << endl;
    for (size_t i = dq.begin(); i <= dq.end(); i++) {
        cout << dq[i] << " ";
    }
    cout << endl;
    //изменили первое значение дека вызовом front()
    dq.front() = 777;
    //изменили промежуточное значение дека вызовом оператора []
    dq[1] = 888;
    //изменили последнее значение дека вызовом back()
    dq.back() = 999;
    cout << "Первое значение дека: " << dq.front() << endl;
    cout << "Промежуточное значение дека: " << dq[1] << endl;
    cout << "Последнее значение дека: " << dq.back() << endl;
 
    cout << "Пуст ли дек? Ответ: " << dq.empty() << endl;
    dq.clear();
    cout << "Очистили дек. Пуст ли дек? Ответ: " << dq.empty() << endl;
 
    dq.assign(5, 9);
    cout << "Воспользовались assign(). \nВывод дека:  ";
    for (size_t i = dq.begin(); i <= dq.end(); i++) {
        cout << dq[i] << " ";
    }
    cout << endl << "Размер дека: " << dq.size() << endl;
    dq.insert(dq.begin(), 0);
    cout << endl << "Воспользовались insert() для begin(). \nВывод дека:  ";
    for (size_t i = dq.begin(); i <= dq.end(); i++) {
        cout << dq[i] << " ";
    }
    dq.pop_back();
    dq.pop_front();
    cout << endl << "Воспользовались pop_back() и pop_front(). \nВывод дека:  ";
    for (size_t i = dq.begin(); i <= dq.end(); i++) {
        cout << dq[i] << " ";
    }
    dq.push_back(-5);
    dq.push_front(-5);
    cout << endl << "Воспользовались push_back() и push_front(). \nВывод дека:  ";
    for (size_t i = dq.begin(); i <= dq.end(); i++) {
        cout << dq[i] << " ";
    }
    cout << endl;
    return 0;
}
0
фрилансер
 Аватар для Алексей1153
6449 / 5643 / 1129
Регистрация: 11.10.2019
Сообщений: 15,025
03.08.2021, 20:37
Лучший ответ Сообщение было отмечено spoilsport как решение

Решение

Цитата Сообщение от spoilsport Посмотреть сообщение
(const size_t& _size)
Цитата Сообщение от spoilsport Посмотреть сообщение
(const size_t& pos)
это в аргументах функций лучше заменить на const size_t _size,const size_t pos (по значению)

Цитата Сообщение от spoilsport Посмотреть сообщение
~deque() {
        /*if (d_size)*/ {
            delete[] a;
        }
d_size=0;
    }
нужно убрать лишнюю проверку. И обнулить d_size


поскольку поля инициализированы в классе, то
Цитата Сообщение от spoilsport Посмотреть сообщение
deque() : d_size(0), a() {}
->
C++
1
deque() =default;

тут не хватает константности
Цитата Сообщение от spoilsport Посмотреть сообщение
bool empty() const{
Цитата Сообщение от spoilsport Посмотреть сообщение
size_t size() const{

пропущено обнуление
Цитата Сообщение от spoilsport Посмотреть сообщение
void clear() {
        delete[] a;
a=nullptr;
        d_size = 0;
    }

кстати, в деструкторе можно вызвать clear()
1
 Аватар для spoilsport
1 / 1 / 0
Регистрация: 17.08.2020
Сообщений: 19
03.08.2021, 20:58  [ТС]
Алексей1153,
Цитата Сообщение от Алексей1153 Посмотреть сообщение
это в аргументах функций лучше заменить на const size_t _size,const size_t pos (по значению)
Я думал, что при передаче по ссылке мы выигрываем во времени из-за того, что не приходится делать копию значения, а учитывая, что аргументы константные их значения не изменятся.

Цитата Сообщение от Алексей1153 Посмотреть сообщение
нужно убрать лишнюю проверку. И обнулить d_size
Цитата Сообщение от Алексей1153 Посмотреть сообщение
кстати, в деструкторе можно вызвать clear()
Да, правда, я немного ступил

Цитата Сообщение от Алексей1153 Посмотреть сообщение
deque() =default;
круто, почитаю про default, спасибо.

Цитата Сообщение от Алексей1153 Посмотреть сообщение
тут не хватает константности
Цитата Сообщение от Алексей1153 Посмотреть сообщение
пропущено обнуление
забыл добавить, исправил

Спасибо
Кликните здесь для просмотра всего текста

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
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
/*
 Ниже представлена программный код реализации дека на базе динамического массива.
 Удалось реализовать методы:
 assign, front, back, size, empty, begin, end, insert(pos,val),
 push_front, push_back, pop_front, pop_back, clear
*/
#include <iostream>
 
template <typename T>
class deque
{
private:
    T* a{};
    size_t d_size{};
 
public:
    deque() = default;
    deque(const deque<T>& _deque) {
        *this = _deque;
    }
    deque(const size_t& _size, const T& val) {
        a = new T[_size];
        for (size_t i = 0; i < _size; i++) {
            a[i] = val;
        }
        d_size = _size;
    }
    deque(const size_t& _size) {
        a = new T[_size];
        for (size_t i = 0; i < _size; i++) {
            a[i] = 0;
        }
        d_size = _size;
    }
    ~deque() {
        clear();
    }
 
    void assign(const size_t& _size, const T& val) {
        if (d_size) delete[] a;
        a = new T[_size];
        for (size_t i = 0; i < _size; i++) {
            a[i] = val;
        }
        d_size = _size;
    }
 
    T& front() {
        return a[0];
    }
 
    T& back() {
        return a[d_size - 1];
    }
 
    size_t size() const {
        return d_size;
    }
 
    bool empty() const {
        return d_size == 0;
    }
 
    size_t begin() const {
        return 0;
    }
 
    size_t end() const {
        if (d_size) return d_size - 1;
        return 0;
    }
 
    void insert(const size_t& pos, const T& val) {
        if (d_size == 0) {
            d_size++;
            a = new T[d_size];
            a[0] = val;
        }
        else {
            d_size++;
            T* temp = new T[d_size];
            for (size_t i = 0; i < pos; i++) {
                temp[i] = a[i];
            }
            temp[pos] = val;
            for (size_t i = pos; i < d_size - 1; i++) {
                temp[i + 1] = a[i];
            }
            delete[] a;
            a = new T[d_size];
            for (size_t i = 0; i < d_size; i++) {
                a[i] = temp[i];
            }
            delete[] temp;
        }
    }
 
    void push_front(const T& val) {
        if (d_size == 0) {
            d_size++;
            a = new T[d_size];
            a[0] = val;
        }
        else {
            d_size++;
            T* temp = new T[d_size];
            temp[0] = val;
            for (size_t i = 0; i < d_size - 1; i++) {
                temp[i + 1] = a[i];
            }
            delete[] a;
            a = new T[d_size];
            for (size_t i = 0; i < d_size; i++) {
                a[i] = temp[i];
            }
            delete[] temp;
        }
    }
 
    void push_back(const T& val) {
        if (d_size == 0) {
            d_size++;
            a = new T[d_size];
            a[0] = val;
        }
        else {
            d_size++;
            T* temp = new T[d_size];
            for (size_t i = 0; i < d_size - 1; i++) {
                temp[i] = a[i];
            }
            delete[] a;
            a = new T[d_size];
            for (size_t i = 0; i < d_size; i++) {
                a[i] = temp[i];
            }
            delete[] temp;
            a[d_size - 1] = val;
        }
    }
 
    void pop_front() {
        if (d_size == 0) {
            throw std::out_of_range("err: out of range");
        }
        else {
            d_size--;
            T* temp = new T[d_size];
            for (size_t i = 0; i < d_size; i++) {
                temp[i] = a[i + 1];
            }
            delete[] a;
            a = new T[d_size];
            for (size_t i = 0; i < d_size; i++) {
                a[i] = temp[i];
            }
            delete[] temp;
        }
    }
 
    void pop_back() {
        if (d_size == 0) {
            throw std::out_of_range("err: out of range");
        }
        else {
            d_size--;
            T* temp = new T[d_size];
            for (size_t i = 0; i < d_size; i++) {
                temp[i] = a[i];
            }
            delete[] a;
            a = new T[d_size];
            for (size_t i = 0; i < d_size; i++) {
                a[i] = temp[i];
            }
            delete[] temp;
        }
    }
 
    void clear() {
        if (d_size) {
            delete[] a;
            a = nullptr;
            d_size = 0;
        }
    }
 
    bool operator==(const deque<T>& _deque) {
        if (d_size != _deque.d_size) return false;
        else {
            for (size_t i = 0; i < d_size; i++) {
                if (a[i] != _deque.a[i]) return false;
            }
        }
        return true;
    }
 
    deque<T>& operator=(const deque<T>& _deque) {
        if (!(*this == _deque) && !(_deque.d_size == 0)) {
            if (d_size != 0) delete[] a;
            d_size = _deque.d_size;
            a = new T[d_size];
            for (size_t i = 0; i < d_size; i++) {
                a[i] = _deque.a[i];
            }
        }
        return *this;
    }
 
    T& operator[](const size_t& pos) {
        if (pos >= d_size) {
            throw std::out_of_range("err: out of range");
        }
        else return a[pos];
    }
};
 
using namespace std;
 
int main()
{
    setlocale(LC_ALL, "ru");
    deque<int> dq(3, 1);
    for (size_t i = dq.begin(); i <= dq.end(); i++) {
        cout << dq[i] << " ";
    }
    //при присваивании самого себя срабатывает проверка, данные не потеряются
    dq = dq;
    cout << endl;
    for (size_t i = dq.begin(); i <= dq.end(); i++) {
        cout << dq[i] << " ";
    }
    cout << endl;
    //изменили первое значение дека вызовом front()
    dq.front() = 777;
    //изменили промежуточное значение дека вызовом оператора []
    dq[1] = 888;
    //изменили последнее значение дека вызовом back()
    dq.back() = 999;
    cout << "Первое значение дека: " << dq.front() << endl;
    cout << "Промежуточное значение дека: " << dq[1] << endl;
    cout << "Последнее значение дека: " << dq.back() << endl;
 
    cout << "Пуст ли дек? Ответ: " << dq.empty() << endl;
    dq.clear();
    cout << "Очистили дек. Пуст ли дек? Ответ: " << dq.empty() << endl;
 
    dq.assign(5, 9);
    cout << "Воспользовались assign(). \nВывод дека:  ";
    for (size_t i = dq.begin(); i <= dq.end(); i++) {
        cout << dq[i] << " ";
    }
    cout << endl << "Размер дека: " << dq.size() << endl;
    dq.insert(dq.begin(), 0);
    cout << endl << "Воспользовались insert() для begin(). \nВывод дека:  ";
    for (size_t i = dq.begin(); i <= dq.end(); i++) {
        cout << dq[i] << " ";
    }
    dq.pop_back();
    dq.pop_front();
    cout << endl << "Воспользовались pop_back() и pop_front(). \nВывод дека:  ";
    for (size_t i = dq.begin(); i <= dq.end(); i++) {
        cout << dq[i] << " ";
    }
    dq.push_back(-5);
    dq.push_front(-5);
    cout << endl << "Воспользовались push_back() и push_front(). \nВывод дека:  ";
    for (size_t i = dq.begin(); i <= dq.end(); i++) {
        cout << dq[i] << " ";
    }
    cout << endl;
    return 0;
}
0
фрилансер
 Аватар для Алексей1153
6449 / 5643 / 1129
Регистрация: 11.10.2019
Сообщений: 15,025
03.08.2021, 21:16
Цитата Сообщение от spoilsport Посмотреть сообщение
Я думал, что при передаче по ссылке мы выигрываем во времени
size_t - маленький объект, сравнимый с размером ссылки. Лучше передавать его по "константному значению"

Добавлено через 3 минуты
Цитата Сообщение от spoilsport Посмотреть сообщение
deque(const size_t& _size) {
        a = new T[_size];
        for (size_t i = 0; i < _size; i++) {
            a[i] = 0;
        }
        d_size = _size;
    }
этот конструктор можно сделать через предыдущий
C++
1
2
3
4
5
6
7
8
9
    deque(const size_t _size, const T& val) {
        a = new T[_size];
        for (size_t i = 0; i < _size; i++) {
            a[i] = val;
        }
        d_size = _size;
    }
    deque(const size_t _size):deque(_size,{}) {
    }
Добавлено через 1 минуту
или даже вот так будет получше
C++
1
2
3
4
    deque(const size_t _size) {
        a = new T[_size]{};
        d_size = _size;
    }
Добавлено через 47 секунд
Цитата Сообщение от spoilsport Посмотреть сообщение
void assign(const size_t& _size, const T& val) {
        if (d_size) delete[] a;
вызвать clear()
1
Неэпический
 Аватар для Croessmah
18144 / 10728 / 2066
Регистрация: 27.09.2012
Сообщений: 27,026
Записей в блоге: 1
03.08.2021, 22:13
Лучший ответ Сообщение было отмечено spoilsport как решение

Решение

spoilsport, предлагаю немного "порефакторить".
Давайте начнем с самого основного - имена.

d_size и a.
Не знаю что значит префикс d_ (наверное, "целое число"?),
но из-за присутствия size в названии понятно что хранит переменная.
А вот что такое a? Просто какая-то безликая буква.
Такое название неприемлемо. Обозвали бы хотя бы data - было бы намного лучше.
Предлагаю ввести концепцию - не статические данные класса начинать с префикса m_.
Переименовываем a в m_data, и d_size в m_size.
С параметрами функции та же беда - почему они то начинаются с подчеркивания, то нет (_size и val)?
Тоже переименовываем. Даже без всяких префиксов - просто уберем подчеркивание.

Теперь пойдем по функциям.

C++
1
2
3
4
5
6
    deque() : m_size(0), m_data(nullptr) {
    }
 
    deque(const deque<T>& src) { 
        *this = src;
    }
<T> - нужно убрать. Внутри шаблона deque и так будет deque<T>.
Почему конструктор копирования не использует список инициализации?
В данном случае у вас размер и указатель являются не инициализированными и при присваивании может быть что угодно.
Предлагаю воспользоваться делегированием:
C++
1
2
3
    deque(const deque& src) : deque() { //<-- делегируем инициализацию конструктору по-умолчанию 
        *this = src;
    }
Не нужно передавать ссылки на int, size_t и т.д. - лучше передайте копию.
В таком случае и const верхнего уровня можно убрать:
deque(size_t size, const T& val) {

У вас же шаблон, а конструктор deque(size_t size) предполагает, что объекту может быть присвоен ноль: m_data[i] = 0;.
Можно также делегировать работу другому конструктору:
C++
1
2
    deque(size_t size): deque(size, T()) {
    }
Вообще, по-факту в данных конструкторах у вас объекты сначала будут инициализированы с помощью инициализации по-умолчанию (что для фундаментальных типов даст мусор), и только потом им присваиваются нужные значения.
Это будет "особенность" данной реализации, связанная с тем, что вы не управляете жизнью отдельных объектов вручную.
Оставим этот вопрос, когда научитесь - перепишите.

C++
1
2
3
4
5
    ~deque() {
        if (m_size) {
            delete[] m_data;
        }
    }
Предлагаю убрать зависимость удаления от размера. Вообще везде. Будем поддерживать инвариант -
m_data либо указывает на выделенную память, либо равен nullptr.
delete, примененный к нулевому указателю ничего не делает.
Плюс у нас есть функция clear, почему бы не позвать её для очистки?
C++
1
2
3
    ~deque() {
        clear();
    }
C++
1
2
3
4
5
6
7
8
    void assign(const size_t& _size, const T& val) {
        if (d_size) delete[] m_data;
        m_data = new T[_size];
        for (size_t i = 0; i < _size; i++) {
            m_data[i] = val;
        }
        m_size = _size;
    }
Здесь меняем всё, следуем всем указаниям выше:
C++
1
2
3
4
5
6
7
8
    void assign(size_t size, const T& val) {
        delete[] m_data;
        m_data = new T[size];
        for (size_t i = 0; i < size; i++) {
            m_data[i] = val;
        }     
        m_size = size;
    }
C++
1
2
3
4
5
6
7
    T& front() {
        return m_data[0];
    }
 
    T& back() {
        return m_data[m_size - 1];
    }
Данные функции нельзя вызывать для константных объектов, что, кажется, неправильно.
Давайте добавим константные версии данных функций:
C++
1
2
3
4
5
6
7
    const T& front() const {
        return m_data[0];
    }
 
    const T& back() const {
        return m_data[m_size - 1];
    }
Далее:
C++
1
2
3
4
5
6
7
    size_t size() {
        return m_size;
    }
 
    bool empty() {
        return m_size == 0;
    }
Эти функции также нельзя вызывать для константных объектов.
Эти функции не меняют объект, также не возвращают наружу ничего, через что можно было бы поменять объект.
Поэтому не будем добавлять константные версии этих функций. Мы просто на эти функции навесим const:
C++
1
2
3
4
5
6
7
    size_t size() const {
        return m_size;
    }
 
    bool empty() const {
        return m_size == 0;
    }
А вот что это за функции - загадка.
C++
1
2
3
4
5
6
7
8
    size_t begin() const {
        return 0;
    }
 
    size_t end() const {
        if (m_size) return m_size- 1;
        return 0;
    }
По идее, begin и end должны возвращать итераторы, а у вас возвращают неизвестно что.
Это индекс первого и последнего элементов? Тогда как отличить пустой дек от дека с одним элементом?
begin и end у них будут равны. Например в цикла ниже это приведет к катастрофе:
C++
1
for (size_t i = dq.begin(); i <= dq.end(); i++) //Для пустого дека будет одна итерация
Давайте просто уберем это безобразие, а когда разберетесь с итераторами - допишите.
Циклы в main сделаем через размер: for (size_t i = 0; i < dq.size(); i++)

Далее insert. Претензии написал в комментариях:
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
    void insert(const size_t& pos, const T& val) {
        //То есть, если дек пуст, то всегда вставляем переданный элемент,
        //    а если дек не пуст, то вставляем в переданную позицию,
        //    и если она неправильная, то будет бяка. Почему такое различие в поведении?
        //Варианта два: либо исключение, либо пусть программист, использующий дек, сам заботиться о правильности позиции.
        //    предлагаю взгромоздить груз ответственности на программиста - пусть думает,
        //    но можете переделать и на выброс исключения.
        //    В этом вопросе я не советчик, так как у вас в каких-то функциях одна стратегия, а в других - другая.
        if (m_size== 0) {
            m_size++;
            m_data = new T[m_size];
            m_data[0] = val;
        }
        else {
            m_size++;
            T* temp = new T[m_size];
            for (size_t i = 0; i < pos; i++) {
                temp[i] = m_data[i];
            }
            temp[pos] = val;
            for (size_t i = pos; i < m_size- 1; i++) {
                temp[i + 1] = m_data[i];
            }
            delete[] m_data;
            
            //У нас temp уже указывает на выделенную память, в которой содержатся все нужные элементы с нужными значениями
            //зачем копировать их еще раз в новыю память?
            //мы можем просто сказать, что m_data теперь указывает на эту память и всё
            m_data = new T[m_size];
            for (size_t i = 0; i < m_size; i++) {
                m_data[i] = temp[i];
            }
            delete[] temp;
        }
    }
После переделки получаем:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
    void insert(size_t pos, const T& val) {
        m_size++;
        T* temp = new T[m_size];
        for (size_t i = 0; i < pos; i++) {
            temp[i] = m_data[i];
        }
        temp[pos] = val;
        for (size_t i = pos; i < m_size - 1; i++) {
            temp[i + 1] = m_data[i];
        }
        delete[] m_data;
        m_data = temp;
    }
К push_front и push_back претензии те же, что и к insert - разное результат для пустого и не пустого дека.
Плюс мы можем использовать insert*:
C++
1
2
3
4
5
6
7
    void push_front(const T& val) {
        insert(0, val);
    }
 
    void push_back(const T& val) {
        insert(m_size, val);
    }
* - вполне вероятно, что было бы возможно сделать push_back и push_front более оптимальными, чем insert, но в данном случае у нас при вставках всё равно выделяется новая память и всё везде копируется, поэтому разницы не будет.

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
    void pop_front() {
        //Вот здесь у вас уже есть проверка.
        //Давайте не будем сейчас заморачиваться и оставим её.
        if (m_size== 0) {
            throw std::out_of_range("err: out of range");
        }
        else {
            m_size--;
            T* temp = new T[m_size];
            for (size_t i = 0; i < m_size; i++) {
                temp[i] = m_data[i + 1];
            }
            delete[] m_data;
            //Вот, здесь снова копирование.
            //У нас уже выделена новая память и на нее уже указывает temp
            //Так что просто присваиваем m_data = temp
            m_data = new T[m_size];
            for (size_t i = 0; i < m_size; i++) {
                m_data[i] = temp[i];
            }
            delete[] temp;
        }
    }
С pop_back та же история. Меняем:
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
    void pop_front() {
        if (m_size== 0) {
            throw std::out_of_range("err: out of range");
        }
 
        //Заметьте, убрана ветка else, т.к. если сработает условие выше, то мы до этого кода уже не дойдем.
        //А вот лишний уровень вложенности только мешает код читать. 
        //В pop_back сделано так же
        m_size--;
        T* temp = new T[m_size];
        for (size_t i = 0; i < m_size; i++) {
            temp[i] = m_data[i + 1];
        }
        delete[] m_data;
        m_data = temp;
    }
 
    void pop_back() {
        if (m_size== 0) {
            throw std::out_of_range("err: out of range");
        }
        m_size--;
        T* temp = new T[m_size];
        for (size_t i = 0; i < m_size; i++) {
            temp[i] = m_data[i];
        }
        delete[] m_data;
        m_data = temp;
    }
Идем дальше по коду:
C++
1
2
3
4
    void clear() {
        delete[] m_data;
        m_size= 0;
    }
Здесь не обнуляется m_data. Помните наш инвариант?
m_data либо указывает на выделенную память, либо имеет значение nullptr:
C++
1
2
3
4
5
    void clear() {
        delete[] m_data;
        m_data = nullptr;
        m_size= 0;
    }
Оператор присваивания.
C++
1
2
3
4
5
6
7
8
    T& operator=(const deque<T>& _deque) {
        if (m_size!= 0) delete[] m_data;
        m_size= _deque.m_size;
        m_data = new T[m_size];
        for (size_t i = 0; i < m_size; i++) {
            m_data[i] = _deque[i];
        }
    }
Как сказали выше - лучше сделать проверку на самоприсваивание.
Также почему оператор присваивания возвращает ссылку на элемент?
Хотя в вашем случае return отсутствует вовсе.
С учетом сказанного выше:
C++
1
2
3
4
5
6
7
8
9
10
11
    deque& operator=(const deque& deque) {
        if (this != &deque) {
            delete[] m_data;
            m_size= deque.m_size;
            m_data = new T[m_size];
            for (size_t i = 0; i < m_size; i++) {
                m_data[i] = deque[i];
            }
        }
        return *this;
    }
В operator[] также меняем всё по рекомендациям:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
    T& operator[](size_t pos) {
        if (pos >= m_size) {
            throw std::out_of_range("err: out of range");
        }
        return m_data[pos];
    }
    
    const T& operator[](size_t pos) const {
        //Добавил и константную версию оператора.
        //Код продублировал, хотя можно было бы сделать и без дублирования,
        //    можете сами подумать (или погуглить) как можно избежать дублирования кода.
        if (pos >= m_size) {
            throw std::out_of_range("err: out of range");
        }
        return m_data[pos];
    }
Итоговая реализация
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
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
/*
 Ниже представлена программный код реализации дека на базе динамического массива.
 Удалось реализовать методы:
 assign, front, back, size, empty, begin, end, insert(pos,val),
 push_front, push_back, pop_front, pop_back, clear
*/
#include <iostream>
 
template <typename T>
class deque
{
private:
    T * m_data;
    size_t m_size;
 
public:
    deque() : m_size(0), m_data(nullptr) {
    }
    
    deque(const deque& src) : deque() {
        *this = src;
    }
    
    deque(size_t size, const T& val) {
        m_data = new T[size];
        for (size_t i = 0; i < size; i++) {
            m_data[i] = val;
        }
        m_size= size;
    }
    
    deque(size_t size): deque(size, T()) {
    }
    
    ~deque() {
        delete[] m_data;
    }
 
    void assign(size_t size, const T& val) {
        delete[] m_data;
        m_data = new T[size];
        for (size_t i = 0; i < size; i++) {
            m_data[i] = val;
        }
        m_size= size;
    }
 
    T& front() {
        return m_data[0];
    }
 
    T& back() {
        return m_data[m_size- 1];
    }
    
    const T& front() const {
        return m_data[0];
    }
 
    const T& back() const {
        return m_data[m_size- 1];
    }
 
    size_t size() const {
        return m_size;
    }
 
    bool empty() const {
        return m_size== 0;
    }
 
    void insert(size_t pos, const T& val) {
        m_size++;
        T* temp = new T[m_size];
        for (size_t i = 0; i < pos; i++) {
            temp[i] = m_data[i];
        }
        temp[pos] = val;
        for (size_t i = pos; i < m_size - 1; i++) {
            temp[i + 1] = m_data[i];
        }
        delete[] m_data;
        m_data = temp;
    }
 
    void push_front(const T& val) {
        insert(0, val);
    }
 
    void push_back(const T& val) {
        insert(m_size, val);
    }
 
    void pop_front() {
        if (m_size == 0) {
            throw std::out_of_range("err: out of range");
        }
 
        //Заметьте, убрана ветка else, т.к. если сработает условие выше, то мы до этого кода уже не дойдем.
        //А вот лишний уровень вложенности только мешает код читать. 
        //В pop_back сделано так же
        m_size--;
        T* temp = new T[m_size];
        for (size_t i = 0; i < m_size; i++) {
            temp[i] = m_data[i + 1];
        }
        delete[] m_data;
        m_data = temp;
    }
 
    void pop_back() {
        if (m_size== 0) {
            throw std::out_of_range("err: out of range");
        }
        m_size--;
        T* temp = new T[m_size];
        for (size_t i = 0; i < m_size; i++) {
            temp[i] = m_data[i];
        }
        delete[] m_data;
        m_data = temp;
    }
 
    void clear() {
        delete[] m_data;
        m_data = nullptr;
        m_size= 0;
    }
 
    deque& operator=(const deque& deque) {
        if (this != &deque) {
            delete[] m_data;
            m_size= deque.m_size;
            m_data = new T[m_size];
            for (size_t i = 0; i < m_size; i++) {
                m_data[i] = deque[i];
            }
        }
        return *this;
    }
 
    T& operator[](size_t pos) {
        if (pos >= m_size) {
            throw std::out_of_range("err: out of range");
        }
        return m_data[pos];
    }
    
    const T& operator[](size_t pos) const {
        //Добавил и константную версию оператора.
        //Код продублировал, хотя можно было бы сделать и без дублирования,
        //    можете сами подумать (или погуглить) как можно избежать дублирования кода.
        if (pos >= m_size) {
            throw std::out_of_range("err: out of range");
        }
        return m_data[pos];
    }
};
 
using namespace std;
 
template<typename T>
std::ostream& operator<<(std::ostream & stream, const deque<T> & dq) {
    for (size_t i = 0; i < dq.size(); i++) {
        stream << dq[i];
        if (i != dq.size() - 1) {
            stream << " "; 
        }
    }
    return stream;
}
 
template<typename T>
void output_deque_and_size(const deque<T> & dq) {
    std::cout 
        << "Вывод дека: " << dq 
        << "\nРазмер дека: " << dq.size() << std::endl;
}
 
 
int main()
{
    setlocale(LC_ALL, "ru");
    deque<int> dq(3);
    output_deque_and_size(dq);
    //изменили первое значение дека вызовом front()
    dq.front() = 777;
    //изменили промежуточное значение дека вызовом оператора []
    dq[1] = 888;
    //изменили последнее значение дека вызовом back()
    dq.back() = 999;
    cout << "Первое значение дека: " << dq.front() << endl;
    cout << "Промежуточное значение дека: " << dq[1] << endl;
    cout << "Последнее значение дека: " << dq.back() << endl;
 
    cout << "Пуст ли дек? Ответ: " << dq.empty() << endl;
    dq.clear();
    cout << "Очистили дек. Пуст ли дек? Ответ: " << dq.empty() << endl;
 
    dq.assign(5, 9);
    cout << "Воспользовались assign(). \n";
    output_deque_and_size(dq);
    
    dq.insert(0, 3);
    cout << endl << "Воспользовались insert() для begin(). \n";
    output_deque_and_size(dq);
    
    dq.pop_back();
    dq.pop_front();
    cout << endl << "Воспользовались pop_back() и pop_front(). \n";
    output_deque_and_size(dq);
    
    dq.push_back(-5);
    cout << endl << "Воспользовались push_back(). \n";
    output_deque_and_size(dq);
    
    dq.push_front(-4);
    cout << endl << "Воспользовались push_front(). \n";
    output_deque_and_size(dq);
    
    cout << endl;
    return 0;
}


Этот код можно (и нужно) еще допиливать и допиливать.
Например, ручное управление объектами, перемещение, exception safety, и т.д.

Добавлено через 4 минуты
https://wandbox.org/permlink/Psgie8OM1CY7hsdE
1
 Аватар для spoilsport
1 / 1 / 0
Регистрация: 17.08.2020
Сообщений: 19
04.08.2021, 13:23  [ТС]
Алексей1153,
Цитата Сообщение от Алексей1153 Посмотреть сообщение
size_t - маленький объект, сравнимый с размером ссылки. Лучше передавать его по "константному значению"
Как я понял, при передаче по ссылке аргумента в функцию сама ссылка занимает определенный размер в памяти (в зависимости от разрядности). Но при передачи по значению же создается копия и тогда мы тоже затрачиваем память. В любом случае я сделаю, как сказали Вы, но пока что запутался, буду читать.

Цитата Сообщение от Алексей1153 Посмотреть сообщение
вызвать clear()
исправил, спасибо.

Croessmah,
Цитата Сообщение от Croessmah Посмотреть сообщение
d_size и a.
Не знаю что значит префикс d_ (наверное, "целое число"?),
но из-за присутствия size в названии понятно что хранит переменная.
А вот что такое a? Просто какая-то безликая буква.
Такое название неприемлемо. Обозвали бы хотя бы data - было бы намного лучше.
Предлагаю ввести концепцию - не статические данные класса начинать с префикса m_.
Переименовываем a в m_data, и d_size в m_size.
С параметрами функции та же беда - почему они то начинаются с подчеркивания, то нет (_size и val)?
Тоже переименовываем. Даже без всяких префиксов - просто уберем подчеркивание.
Да, так будет гораздо лучше и понятнее. С названиями всегда была проблема, сейчас начал заглядывать в коды стандартных библиотек, чтобы что-то оттуда перенять, но не совсем удачно

Цитата Сообщение от Croessmah Посмотреть сообщение
Не нужно передавать ссылки на int, size_t и т.д. - лучше передайте копию.
В таком случае и const верхнего уровня можно убрать:
deque(size_t size, const T& val) {
Алексей1153 тоже предложил не передавать ссылку на size_t, но я не особо понимаю почему так лучше делать. Нашел только информацию о том, что ссылка занимает определенное место в памяти. Если размер копии при передаче по значению меньше чем размер ссылки, то тогда я понимаю. В любом случаю исправлю, как Вы и сказали.
Константу тоже пока не разобрался почему не стоит передавать, считал это хорошим тоном, когда значение, не изменяемое в области видимости функции, помечают константным.

Цитата Сообщение от Croessmah Посмотреть сообщение
Вообще, по-факту в данных конструкторах у вас объекты сначала будут инициализированы с помощью инициализации по-умолчанию (что для фундаментальных типов даст мусор), и только потом им присваиваются нужные значения.
Это будет "особенность" данной реализации, связанная с тем, что вы не управляете жизнью отдельных объектов вручную.
Оставим этот вопрос, когда научитесь - перепишите.
Спасибо, почитаю про это обязательно. Буду сильно благодарен, если у Вас есть какая-то статья или любой наводящий текст на примете

Цитата Сообщение от Croessmah Посмотреть сообщение
По идее, begin и end должны возвращать итераторы, а у вас возвращают неизвестно что.
Это индекс первого и последнего элементов?
Мне тоже не понравилась такая реализация. Я про это и говорил в топике темы, потому что не понял зачем так это работает в <deque>. Ведь по сути мы можем выделить память, например, на 5 элементов, а использовать только 2, тогда стоило бы указывать begin() на 0, а end() на 1.
Цитата Сообщение от spoilsport Посмотреть сообщение
Акцентирую внимание, что просматривал как работает стандартная библиотека <deque>, чтобы не отходить от её функционала. И немного глупо (по-моему мнению) получились методы begin() И end(), так как для очереди может быть выделена память из кучи, но заполнена только до половины, однако метод end() вернет значение на последний "мусорный" элемент очереди. Посмотрел и в <deque> работает это точно также, однако возможно чего то не заметил или не понял.
Цитата Сообщение от Croessmah Посмотреть сообщение
Тогда как отличить пустой дек от дека с одним элементом?
begin и end у них будут равны. Например в цикла ниже это приведет к катастрофе:
Да, мне нужно было добавить хотя бы проверку такого случая. Можно просто выбросить исключение out of range.

Цитата Сообщение от Croessmah Посмотреть сообщение
Давайте просто уберем это безобразие, а когда разберетесь с итераторами - допишите.
Про итераторы знаю, но видимо недостаточно, из-за чего боюсь их использовать. Думаю это отличный момент углубиться в тему

Цитата Сообщение от Croessmah Посмотреть сообщение
В этом вопросе я не советчик, так как у вас в каких-то функциях одна стратегия, а в других - другая.
Долго метался из стороны в сторону, думая сделать простую реализацию без углублений в обработку различных ситуация или проработать всё, из-за чего решил отдать на кодревью сюда, чтобы мне хорошенько стукнули по голове за мою неуверенность и некоторую халатность.

Цитата Сообщение от Croessmah Посмотреть сообщение
//Заметьте, убрана ветка else, т.к. если сработает условие выше, то мы до этого кода уже не дойдем.
        //А вот лишний уровень вложенности только мешает код читать.
        //В pop_back сделано так же
Спасибо, не задумывался над этим. Буду теперь чаще вспоминать про это.

Цитата Сообщение от Croessmah Посмотреть сообщение
Этот код можно (и нужно) еще допиливать и допиливать.
Например, ручное управление объектами, перемещение, exception safety, и т.д.
Да, благодаря вам у меня теперь пополнился список темами к прочтению
Правда, большое спасибо Croessmah и Алексей1153 за ваше потраченное время и такой серьезный подход к разбору кода. Буду стараться, чтобы он теперь был чуточку лучше. Благодарю
0
Неэпический
 Аватар для Croessmah
18144 / 10728 / 2066
Регистрация: 27.09.2012
Сообщений: 27,026
Записей в блоге: 1
04.08.2021, 13:42
Цитата Сообщение от spoilsport Посмотреть сообщение
но я не особо понимаю почему так лучше делать.
size_t - достаточно легкий объект, вполне вероятно, что он вообще будет передан через регистр.
Ссылка - тоже не большая, но внутри функции для получения значения нужно будет делать косвенное обращение.
Оптимизатор может это всё оправить, а может и нет.

Цитата Сообщение от spoilsport Посмотреть сообщение
Константу тоже пока не разобрался почему не стоит передавать, считал это хорошим тоном, когда значение, не изменяемое в области видимости функции, помечают константным.
Если передаете ссылку или указатель на объект, который не нужно менять, то да.
А если передается копия объекта, то нет никакой необходимости делать параметр константным.
Хотя если того требует code-style, то можно и написать. При этом внутри функции параметр будет константным.

Цитата Сообщение от spoilsport Посмотреть сообщение
Я про это и говорил в топике темы, потому что не понял зачем так это работает в <deque>. Ведь по сути мы можем выделить память, например, на 5 элементов, а использовать только 2, тогда стоило бы указывать begin() на 0, а end() на 1.
В deque как раз "ручное" управление объектами.
То есть объекты создаются и освобождаются по запросу.
Если есть возможность, то другие объекты никак не затрагиваются.
1
19491 / 10097 / 2460
Регистрация: 30.01.2014
Сообщений: 17,805
04.08.2021, 13:45
Цитата Сообщение от spoilsport Посмотреть сообщение
Как я понял, при передаче по ссылке аргумента в функцию сама ссылка занимает определенный размер в памяти (в зависимости от разрядности). Но при передачи по значению же создается копия и тогда мы тоже затрачиваем память. В любом случае я сделаю, как сказали Вы, но пока что запутался, буду читать.
Передавать ссылку - это еще и медленнее, несмотря на размеры.
Потому что вы вынуждаете компилятор везде в этих местах делать косвенный доступ.

Добавлено через 2 минуты
Цитата Сообщение от Croessmah Посмотреть сообщение
Оптимизатор может это всё оправить, а может и нет.
Если функция не встраивается, то не может. Если есть вызов, то и косвенный доступ будет всегда. Причем во всех местах использования. "Кешировать" значение, полученное по ссылке, внутри функции компилятор не станет.
1
04.08.2021, 13:57

Не по теме:

Цитата Сообщение от DrOffset Посмотреть сообщение
Если функция не встраивается, то не может.
В данном случае у ТС'а шаблон и определение доступно, шанс есть.

0
 Аватар для spoilsport
1 / 1 / 0
Регистрация: 17.08.2020
Сообщений: 19
04.08.2021, 15:09  [ТС]
Croessmah,
Цитата Сообщение от Croessmah Посмотреть сообщение
size_t - достаточно легкий объект, вполне вероятно, что он вообще будет передан через регистр.
Ссылка - тоже не большая, но внутри функции для получения значения нужно будет делать косвенное обращение.
Оптимизатор может это всё оправить, а может и нет.
Кажется приблизительно понял, спасибо.

Цитата Сообщение от Croessmah Посмотреть сообщение
А если передается копия объекта, то нет никакой необходимости делать параметр константным.
Теперь понимаю почему это выглядит глупо, это логично, ведь мы никак не влияем на переданных аргумент, только на его копию. Понял, спасибо.

DrOffset,
Цитата Сообщение от DrOffset Посмотреть сообщение
Передавать ссылку - это еще и медленнее, несмотря на размеры.
Потому что вы вынуждаете компилятор везде в этих местах делать косвенный доступ.
Хорошо, видимо нужно прочувствовать это на уровне ассемблера, чтобы таких ошибок не допускать. Спасибо
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
04.08.2021, 15:09
Помогаю со студенческими работами здесь

Хранение в контейнере deque целых чисел и проверка основных операций
Написала код: #include &quot;stdafx.h&quot; #include &lt;iostream&gt; #include &lt;deque&gt; using namespace std; void show (const char *str,...

Проверка знаний по C++
Оцените правильность моих ответов пожалуйста. Всего было 100 вопросов. Я оставил только те, в которых сомневаюсь. Тест дали в университете....

Программа - проверка знаний
Изучаю Qt Creator и нужно написать программу тестирование, которая будет состоять из нескольких тем тестов, варианты в вопросах будут...

Проверка знаний таблицы умножения
Доброго времени суток! есть задача: Написать программу, которая проверяет пользователя на знание таблицы умножения. Программа выводит...

Проверка знаний таблицы умножения
Пользователь сам вводит два целых однозначных числа. Программа задаёт вопрос: результат умножения первого числа на второе. Пользователь...


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

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Новые блоги и статьи
сукцессия микоризы: основная теория в виде двух уравнений.
anaschu 11.01.2026
https:/ / rutube. ru/ video/ 7a537f578d808e67a3c6fd818a44a5c4/
WordPad для Windows 11
Jel 10.01.2026
WordPad для Windows 11 — это приложение, которое восстанавливает классический текстовый редактор WordPad в операционной системе Windows 11. После того как Microsoft исключила WordPad из. . .
Classic Notepad for Windows 11
Jel 10.01.2026
Old Classic Notepad for Windows 11 Приложение для Windows 11, позволяющее пользователям вернуть классическую версию текстового редактора «Блокнот» из Windows 10. Программа предоставляет более. . .
Почему дизайн решает?
Neotwalker 09.01.2026
В современном мире, где конкуренция за внимание потребителя достигла пика, дизайн становится мощным инструментом для успеха бренда. Это не просто красивый внешний вид продукта или сайта — это. . .
Модель микоризы: классовый агентный подход 3
anaschu 06.01.2026
aa0a7f55b50dd51c5ec569d2d10c54f6/ O1rJuneU_ls https:/ / vkvideo. ru/ video-115721503_456239114
Owen Logic: О недопустимости использования связки «аналоговый ПИД» + RegKZR
ФедосеевПавел 06.01.2026
Owen Logic: О недопустимости использования связки «аналоговый ПИД» + RegKZR ВВЕДЕНИЕ Введу сокращения: аналоговый ПИД — ПИД регулятор с управляющим выходом в виде числа в диапазоне от 0% до. . .
Модель микоризы: классовый агентный подход 2
anaschu 06.01.2026
репозиторий https:/ / github. com/ shumilovas/ fungi ветка по-частям. коммит Create переделка под биомассу. txt вход sc, но sm считается внутри мицелия. кстати, обьем тоже должен там считаться. . . .
Расчёт токов в цепи постоянного тока
igorrr37 05.01.2026
/ * Дана цепь постоянного тока с сопротивлениями и источниками (напряжения, ЭДС и тока). Найти токи и напряжения во всех элементах. Программа составляет систему уравнений по 1 и 2 законам Кирхгофа и. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru