|
1 / 1 / 0
Регистрация: 17.08.2020
Сообщений: 19
|
||||||
Дек (deque) - проверка знаний03.08.2021, 13:42. Показов 4545. Ответов 27
Добрый день/вечер/ночь.
Захотел воспользоваться знаниями опытных программистов этого форума и получить критику по ниже представленному "коду" ![]() Очень интересны абсолютно любые замечания, касающиеся стиля (если он там есть), работой с памятью и изобретенных велосипедов. Понимаю, что снизу представлен слишком скудноватый на строки код, чтобы по нему делать какие-то выводы, но уверен, что даже в нем находятся ошибки, которых я не замечаю ввиду своей неопытности. Итак, ниже я попытался написать дек при помощи динамического массива. Акцентирую внимание, что просматривал как работает стандартная библиотека <deque>, чтобы не отходить от её функционала. И немного глупо (по-моему мнению) получились методы begin() И end(), так как для очереди может быть выделена память из кучи, но заполнена только до половины, однако метод end() вернет значение на последний "мусорный" элемент очереди. Посмотрел и в <deque> работает это точно также, однако возможно чего то не заметил или не понял. Здесь ссылка на GitHub, если понадобится: https://github.com/spo1lsp0rt/deque_darr Ниже также находится вывод в консоль. Заранее благодарю за потраченное вами время ![]() Код: Кликните здесь для просмотра всего текста
Вывод в консоли: Кликните здесь для просмотра всего текста
Первое значение дека: 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
|
||||||
| 03.08.2021, 13:42 | |
|
Ответы с готовыми решениями:
27
Deque (Дек) на двусвязном списке Создание ДЕК (как стэк только о двух концах) без <deque> Есть ли в Qt контейнер типа "Дек" (deque) или надо свой написать? |
|
8973 / 4319 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
|
||
| 03.08.2021, 14:48 | ||
|
его нужно сначала проверить. исправить все явные ошибки, недочеты, а так же косяки, о которых тебе сообщает компилятор и только потом выкладывать на code-review. сейчас рассматривать твой код нет никакого смысла. вот когда ты исправишь все явные косяки, вот тогда и приходи.
0
|
||
|
1 / 1 / 0
Регистрация: 17.08.2020
Сообщений: 19
|
||||||
| 03.08.2021, 15:06 [ТС] | ||||||
|
Здравствуйте.
Если я правильно понял, то Вы имели ввиду предупреждения. Неправильно очищал память от данных. Однако в остальном код работает исправно. Исправления прикрепил ниже. Кликните здесь для просмотра всего текста
0
|
||||||
|
фрилансер
6463 / 5671 / 1131
Регистрация: 11.10.2019
Сообщений: 15,109
|
|
| 03.08.2021, 15:11 | |
|
spoilsport, по меньшей мере: конструктор по умолчанию, деструктор (освобождать память то надо?), использован
unsigned int вместо size_t ![]() Добавлено через 46 секунд NULL -> nullptr
0
|
|
|
1 / 1 / 0
Регистрация: 17.08.2020
Сообщений: 19
|
|||
| 03.08.2021, 15:51 [ТС] | |||
|
hoggy, Cпасибо за такой полезный сайт
Дело в том, что я пользуюсь лишь информацией, которую выдает мне мой компилятор и такого количества как у Вас - у меня не было. Сейчас просмотрю все и подправлю.Добавлено через 3 минуты Алексей1153,
0
|
|||
|
8973 / 4319 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
|
||
| 03.08.2021, 16:14 | ||
|
у компиляторов есть такое понятие: "уровень предупреждений". чем он выше, тем больше всяких косяков показывает компилятор. на максимальных уровнях компиляторы начинают докалебываться до каждой запятой. и именно такой уровень используют люди, которые хотят получить качественный код. как именно настраивается твой компилятор, описано в его документации. я не знаю какой у тебя компилятор, но если у тебя, например, компилятор Visual Studio, то почитать можно здесь. мой опыт показывает: что бы гарантировать высокое качество кода, недостаточно протестировать его только на одном компиляторе. необходимо запускать сразу множество сборок, на множестве разных компиляторов, во множестве различных конфигураций. и для всех этих сборок необходимо запускать юнит-тесты. и если хотя бы один компилятор покажет хотя бы один ворнинг - код отправится на доработку. если хотя бы одна сборка зафейлит хотя бы один юнит-тест - код отправится на доработку. мой опыт показывает: редко когда код сразу получается качественным. обычно на практике он по многу раз отправляется на доработку.
1
|
||
|
1 / 1 / 0
Регистрация: 17.08.2020
Сообщений: 19
|
||||||
| 03.08.2021, 17:34 [ТС] | ||||||
|
hoggy, спасибо большое, мне это поможет в будущем. Нашел как настроить "уровень предупреждений" в VS, классно, что теперь знаю о такой функции.
Исправил код, предупреждений больше не выдает, кроме совета об использовании списка инициализации для одного из конструкторов. Но я не могу переписать конструктор под такой механизм, потому что нужно использование цикла. Понимаю, что это не то, что нужно отправлять на кодревью. Необходимо просто практиковаться больше, но я надеялся подчеркнуть ошибки уже на этой стадии. И я уже узнал много чего интересного из этой темы ![]() Поэтому если у Вас будет свободное время, посмотрите пожалуйста мой бедо-код. Кликните здесь для просмотра всего текста
0
|
||||||
|
фрилансер
6463 / 5671 / 1131
Регистрация: 11.10.2019
Сообщений: 15,109
|
|||||||||
| 03.08.2021, 18:01 | |||||||||
|
там имеется в виду инициализация полей deque(const size_t& _size) :d_size{}, a{} { ну и ещё обращается внимание на порядок инициализации - он должен соответствовать порядку полей в классе а вообще, лучше прямо в месте объявления полей в классе инициализацию задать
1
|
|||||||||
|
Неэпический
|
|||||||||||
| 03.08.2021, 18:14 | |||||||||||
_deque.d_size окажется равным нулю, то в результате будет течь память, т.к. везде перед delete [] a идут проверки именно по d_size.
1
|
|||||||||||
|
1 / 1 / 0
Регистрация: 17.08.2020
Сообщений: 19
|
|||||||||||||||||||||||||||||||||
| 03.08.2021, 20:24 [ТС] | |||||||||||||||||||||||||||||||||
|
Алексей1153,
Кликните здесь для просмотра всего текста
Кликните здесь для просмотра всего текста
Добавлено через 19 минут Кликните здесь для просмотра всего текста
Когда же мы пишем как ниже, происходит именно передача адреса второго указателя в ячейку памяти первого указателя. И в таком случае, после удаления p2 указателя происходит разрыв связи первого указателя p1 со вторым p2. Кликните здесь для просмотра всего текста
Но когда я делал, как указали Вы, происходило так же как и во втором случае. Хотя казалось бы (как я понимаю) при a = temp создается копия temp'a и присваивается деку a. Вот я и встал в ступор. При очистке памяти временного temp дека почему то очищалась память и для основного дека. Когда же я убрал очистку временного дека delete[] temp, в основном деке оставались значения временного. Но я не понял почему, ведь по сути область видимости временного temp дека заканчивается при выходе из метода и он все равно очищается (поправьте, пожалуйста, если я косячник и не прав). Мне не понравилась вся эта ситуация, и поэтому я решил на время сделать именно ту запись, которую Вы видели. ![]() Добавлено через 22 минуты Добавлено через 19 минут Исправил все замечания выше. Еще раз благодарю за такую помощь, думаю мне это действительно помогает ![]() Кликните здесь для просмотра всего текста
0
|
|||||||||||||||||||||||||||||||||
|
фрилансер
6463 / 5671 / 1131
Регистрация: 11.10.2019
Сообщений: 15,109
|
|||||||||||||
| 03.08.2021, 20:37 | |||||||||||||
Сообщение было отмечено spoilsport как решение
Решениеconst size_t _size,const size_t pos (по значению)поскольку поля инициализированы в классе, то
тут не хватает константности пропущено обнуление кстати, в деструкторе можно вызвать clear()
1
|
|||||||||||||
|
1 / 1 / 0
Регистрация: 17.08.2020
Сообщений: 19
|
||||||||||||
| 03.08.2021, 20:58 [ТС] | ||||||||||||
|
Алексей1153,
![]() Спасибо Кликните здесь для просмотра всего текста
0
|
||||||||||||
|
фрилансер
6463 / 5671 / 1131
Регистрация: 11.10.2019
Сообщений: 15,109
|
||||||||||||||
| 03.08.2021, 21:16 | ||||||||||||||
|
Добавлено через 3 минуты
или даже вот так будет получше
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)?Тоже переименовываем. Даже без всяких префиксов - просто уберем подчеркивание. Теперь пойдем по функциям.
<T> - нужно убрать. Внутри шаблона deque и так будет deque<T>.Почему конструктор копирования не использует список инициализации? В данном случае у вас размер и указатель являются не инициализированными и при присваивании может быть что угодно. Предлагаю воспользоваться делегированием:
int, size_t и т.д. - лучше передайте копию.В таком случае и const верхнего уровня можно убрать: deque(size_t size, const T& val) {У вас же шаблон, а конструктор deque(size_t size) предполагает, что объекту может быть присвоен ноль: m_data[i] = 0;.Можно также делегировать работу другому конструктору:
Это будет "особенность" данной реализации, связанная с тем, что вы не управляете жизнью отдельных объектов вручную. Оставим этот вопрос, когда научитесь - перепишите. ![]()
m_data либо указывает на выделенную память, либо равен nullptr.delete, примененный к нулевому указателю ничего не делает. Плюс у нас есть функция clear, почему бы не позвать её для очистки?
Давайте добавим константные версии данных функций:
Эти функции не меняют объект, также не возвращают наружу ничего, через что можно было бы поменять объект. Поэтому не будем добавлять константные версии этих функций. Мы просто на эти функции навесим const:
Это индекс первого и последнего элементов? Тогда как отличить пустой дек от дека с одним элементом? begin и end у них будут равны. Например в цикла ниже это приведет к катастрофе:
![]() Циклы в main сделаем через размер: for (size_t i = 0; i < dq.size(); i++)Далее insert. Претензии написал в комментариях:
Плюс мы можем использовать insert*:
pop_back та же история. Меняем:
m_data либо указывает на выделенную память, либо имеет значение nullptr:
Также почему оператор присваивания возвращает ссылку на элемент? Хотя в вашем случае return отсутствует вовсе.С учетом сказанного выше:
Итоговая реализация
Этот код можно (и нужно) еще допиливать и допиливать. Например, ручное управление объектами, перемещение, exception safety, и т.д. Добавлено через 4 минуты https://wandbox.org/permlink/Psgie8OM1CY7hsdE
1
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
1 / 1 / 0
Регистрация: 17.08.2020
Сообщений: 19
|
|||||||||||||
| 04.08.2021, 13:23 [ТС] | |||||||||||||
|
Алексей1153,
Croessmah, Константу тоже пока не разобрался почему не стоит передавать, считал это хорошим тоном, когда значение, не изменяемое в области видимости функции, помечают константным. ![]() ![]() Правда, большое спасибо Croessmah и Алексей1153 за ваше потраченное время и такой серьезный подход к разбору кода. Буду стараться, чтобы он теперь был чуточку лучше. Благодарю
0
|
|||||||||||||
|
Неэпический
|
||||
| 04.08.2021, 13:42 | ||||
size_t - достаточно легкий объект, вполне вероятно, что он вообще будет передан через регистр.Ссылка - тоже не большая, но внутри функции для получения значения нужно будет делать косвенное обращение. Оптимизатор может это всё оправить, а может и нет. А если передается копия объекта, то нет никакой необходимости делать параметр константным. Хотя если того требует code-style, то можно и написать. При этом внутри функции параметр будет константным. deque как раз "ручное" управление объектами. То есть объекты создаются и освобождаются по запросу. Если есть возможность, то другие объекты никак не затрагиваются.
1
|
||||
|
19500 / 10105 / 2461
Регистрация: 30.01.2014
Сообщений: 17,818
|
|||
| 04.08.2021, 13:45 | |||
|
Потому что вы вынуждаете компилятор везде в этих местах делать косвенный доступ. Добавлено через 2 минуты
1
|
|||
| 04.08.2021, 13:57 | |
|
0
|
|
|
1 / 1 / 0
Регистрация: 17.08.2020
Сообщений: 19
|
||||
| 04.08.2021, 15:09 [ТС] | ||||
|
Croessmah,
DrOffset,
0
|
||||
| 04.08.2021, 15:09 | |
|
Помогаю со студенческими работами здесь
20
Хранение в контейнере deque целых чисел и проверка основных операций Проверка знаний по C++
Искать еще темы с ответами Или воспользуйтесь поиском по форуму: |
|
Новые блоги и статьи
|
|||
|
SDL3 для Desktop (MinGW): Рисуем цветные прямоугольники с помощью рисовальщика SDL3 на Си и C++
8Observer8 17.03.2026
Содержание блога
Финальные проекты на Си и на C++:
finish-rectangles-sdl3-c. zip
finish-rectangles-sdl3-cpp. zip
|
Символические и жёсткие ссылки в Linux.
algri14 15.03.2026
Существует два типа ссылок — символические и жёсткие.
Ссылка в Linux — это запись в каталоге, которая может указывать либо на inode «файла-ИСТОЧНИКА», тогда это будет «жёсткая ссылка» (hard link),. . .
|
[Owen Logic] Поддержание уровня воды в резервуаре количеством включённых насосов: моделирование и выбор регулятора
ФедосеевПавел 14.03.2026
Поддержание уровня воды в резервуаре количеством включённых насосов: моделирование и выбор регулятора
ВВЕДЕНИЕ
Выполняя задание на управление насосной группой заполнения резервуара,. . .
|
делаю науч статью по влиянию грибов на сукцессию
anaschu 13.03.2026
прикрепляю статью
|
|
SDL3 для Desktop (MinGW): Создаём пустое окно с нуля для 2D-графики на SDL3, Си и C++
8Observer8 10.03.2026
Содержание блога
Финальные проекты на Си и на C++:
hello-sdl3-c. zip
hello-sdl3-cpp. zip
Результат:
|
Установка CMake и MinGW 13.1 для сборки С и C++ приложений из консоли и из Qt Creator в EXE
8Observer8 10.03.2026
Содержание блога
MinGW - это коллекция инструментов для сборки приложений в EXE. CMake - это система сборки приложений. Здесь описаны базовые шаги для старта программирования с помощью CMake и. . .
|
Как дизайн сайта влияет на конверсию: 7 решений, которые реально повышают заявки
Neotwalker 08.03.2026
Многие до сих пор воспринимают дизайн сайта как “красивую оболочку”. На практике всё иначе: дизайн напрямую влияет на то, оставит человек заявку или уйдёт через несколько секунд.
Даже если у вас. . .
|
Модульная разработка через nuget packages
DevAlt 07.03.2026
Сложившийся в . Net-среде способ разработки чаще всего предполагает
монорепозиторий в котором находятся все исходники.
При создании нового решения, мы просто добавляем нужные проекты
и имеем. . .
|