Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.60/5: Рейтинг темы: голосов - 5, средняя оценка - 4.60
0 / 0 / 0
Регистрация: 07.09.2024
Сообщений: 3

Шаблонная циклическая очередь

07.09.2024, 14:45. Показов 1365. Ответов 5

Студворк — интернет-сервис помощи студентам
Имеется следующее задание:
Необходимо написать шаблонную циклическую очередь, безопасную для одновременной записи и чтения из двух потоков (один поток читает, другой пишет), без механизмов взаимной блокировки потоков. К очереди предъявляются следующие требования:
  1. Память для хранения данных аллоцируется статически внутри очереди;
  2. Два шаблонных параметра: тип данных очереди и максимальное количество хранимых элементов этого типа;
  3. Поддержка конструктора копирования и оператора присваивания.
Я написал класс Queue (представлен ниже), но мне сказали, что в реализации есть ошибки:
  1. Нарушено условие о статической аллокации памяти;
  2. Элементы очереди хранятся в ней пока не будут перезаписаны новыми данными (необходимо уничтожать элементы при извлечении).
  3. Необходимо исправить код так, чтобы достаточно было наличия в классе конструктор копирования, без оператора присваивания.
В связи с этим у меня есть вопросы:
  1. Если мой вариант создания переменной не статический, то нужно использовать модификатор static? Если так, то какой смысл в конструкторе копирования? static члены класса же будут одинаковы для всех экземпляров класса.
  2. Есть ли вариант уничтожать переменные, кроме как присваивать элементу массива новое значение, например NULL
  3. Необходимо ли менять конструктор копирования?

Queue.h:
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
#pragma once
#include <iostream>
#define QUEUE_IS_EMPTY -1
 
#define QUEUE_TEMPLATE template <typename T, const int CAPACITY> // Использование шаблонных параметров
 
QUEUE_TEMPLATE
class Queue {
private:
    int firstElementPos; // Первый элемент очереди ("QUEUE_IS_EMPTY" - очередь пуста)
    int lastElementPos; // Последний элемент очереди ("QUEUE_IS_EMPTY" - очередь пуста)
 
    // Статическое выделение памяти
    T queueOfElements[CAPACITY] = {};   // Массив для хранения данных
 
public:
    Queue(); // Конструктор
 
    Queue(const Queue& other); // Конструктор копирования
 
    Queue& operator=(const Queue& other); // Оператор присваивания
 
    bool queueIsFull(); // Проверка заполненности очереди
 
    bool queueIsEmpty(); // Проверка очереди на отсутствие элементов
 
    bool addToQueue(T newElement); // Добавление элемента в очередь true - удачно, false - очередь заполнена
 
    T takeFromQueue(); // Получение элемента из очереди
 
    int printQueueSize(); // Возвращает текущее количество элементов в очереди
 
    ~Queue(); // Деструктор
 
};
Queue.cpp:
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
#include "Queue.h"
 
// Конструктор
QUEUE_TEMPLATE
Queue<T, CAPACITY>::Queue() : firstElementPos(QUEUE_IS_EMPTY), lastElementPos(QUEUE_IS_EMPTY)
{
    // ctor
}
 
// Конструктор копирования
QUEUE_TEMPLATE
Queue<T, CAPACITY>::Queue(const Queue& other) : firstElementPos(other.firstElementPos), lastElementPos(other.lastElementPos)
{
    if (lastElementPos != QUEUE_IS_EMPTY) // Если присваивается не пустая очередь
    {
        if (lastElementPos == firstElementPos) // Очередь содержит всего один элемент
        {
            this->queueOfElements[firstElementPos] = other.queueOfElements[firstElementPos];
        }
        else if (lastElementPos > firstElementPos) // Последний элемент в массиве позже первого
        {
            for (auto i = firstElementPos; i <= lastElementPos; i++)
            {
                this->queueOfElements[i] = other.queueOfElements[i];
            }
        }
        else // lastElementPos < firstElementPos // Последний элемент в массиве раньше первого
        {
            for (auto i = 0; i <= lastElementPos; i++) // 0 - last
            {
                this->queueOfElements[i] = other.queueOfElements[i];
            }
            for (auto i = firstElementPos; i <= CAPACITY; i++) // first - CAPACITY
            {
                this->queueOfElements[i] = other.queueOfElements[i];
            }
        }
    }
}
 
// Оператор присваивания
QUEUE_TEMPLATE
Queue<T, CAPACITY>& Queue<T, CAPACITY>::operator=(const Queue& other)
{
    if (&other != this)
    {
        this->firstElementPos = other.firstElementPos;
        this->lastElementPos = other.lastElementPos;
 
        if (lastElementPos != QUEUE_IS_EMPTY) // Если присваивается не пустая очередь
        {
            if (lastElementPos == firstElementPos) // Очередь содержит всего один элемент
            {
                this->queueOfElements[firstElementPos] = other.queueOfElements[firstElementPos];
            }
            else if (lastElementPos > firstElementPos) // Последний элемент в массиве позже первого
            {
                for (auto i = firstElementPos; i <= lastElementPos; i++)
                {
                    this->queueOfElements[i] = other.queueOfElements[i];
                }
            }
            else // lastElementPos < firstElementPos // Последний элемент в массиве раньше первого
            {
                for (auto i = 0; i <= lastElementPos; i++) // 0 - last
                {
                    this->queueOfElements[i] = other.queueOfElements[i];
                }
                for (auto i = firstElementPos; i <= CAPACITY; i++) // first - CAPACITY
                {
                    this->queueOfElements[i] = other.queueOfElements[i];
                }
            }
        }
    }
    return *this;
}
 
// queueIsFull
QUEUE_TEMPLATE
bool Queue<T, CAPACITY>::queueIsFull() // Проверка заполненности очереди
{
    if ((firstElementPos == 0 && lastElementPos == CAPACITY - 1) || (firstElementPos == lastElementPos + 1))
    {
        return true; // Очередь заполнена
    }
    else
    {
        return false; // Очередь имеет свободное место
    }
}
 
// queueIsEmpty
QUEUE_TEMPLATE
bool Queue<T, CAPACITY>::queueIsEmpty() // Проверка очереди на отсутствие элементов
{
    if (firstElementPos == QUEUE_IS_EMPTY)
    {
        return true; // Очередь пустая
    }
    else
    {
        return false; // Очередь содержит элементы
    }
}
 
// addToQueue
QUEUE_TEMPLATE
bool Queue<T, CAPACITY>::addToQueue(T newElement) { // Добавление элемента в очередь true - удачно, false - очередь заполнена
    if (queueIsFull())
    {
        return false; // Очередь заполнена
    }
    else
    {
        if (queueIsEmpty())
        {
            firstElementPos = 0; // Если очередь пустая - заполнение с 0-го элемента
        }
        auto newLastElem = (lastElementPos + 1) % CAPACITY; // Новая позиция последнего элемента
        queueOfElements[newLastElem] = newElement;          // Запись нового элемента в очередь
        lastElementPos = newLastElem;                       // Запись новой позиции последнего элемента
 
        return true; // Элемент добавлен в очередь
    }
}
 
// takeFromQueue
QUEUE_TEMPLATE
T Queue<T, CAPACITY>::takeFromQueue() { // Получение элемента из очереди
    if (queueIsEmpty())
    {
        return NULL; // Очередь пустая
    }
 
    T element;
    element = queueOfElements[firstElementPos]; // Запись первого элемента из очереди
 
    if (firstElementPos == lastElementPos)
    {
        firstElementPos = QUEUE_IS_EMPTY;   // Если выдан последний элемент в очереди
        lastElementPos = QUEUE_IS_EMPTY;    // возврат к "пустому" состоянию
    }
    else
    {
        firstElementPos = (firstElementPos + 1) % CAPACITY; // Если в очереди остались элементы - сдвиг позиции первого
    }
    return element; // Передача первого элемента из очереди
}
 
// printQueueSize
QUEUE_TEMPLATE
int Queue<T, CAPACITY>::printQueueSize() { // Возвращает текущее количество элементов в очереди
 
    if (queueIsEmpty()) {
        return QUEUE_IS_EMPTY; // Очередь пустая
    }
    else
    {
        // Подсчет количества элементов
        if (lastElementPos >= firstElementPos)
        {
            return lastElementPos - firstElementPos + 1;
        }
        else
        {
            return lastElementPos - firstElementPos + 1 + CAPACITY;
        }
    }
}
 
// Деструктор
QUEUE_TEMPLATE
Queue<T, CAPACITY>::~Queue()
{
    // dtor
}
main.cpp:
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
#include <iostream>
 
#include "Queue.h"
#include "Queue.cpp"
 
int main() {
 
    Queue<int, 5> q; // Создание экземпляра
 
    std::cout << q.takeFromQueue() << std::endl; // Попытка взять из очереди. False, потому что очередь пуста
 
    q.addToQueue(1); // Заполнение очереди
    q.addToQueue(2);
    q.addToQueue(3);
    q.addToQueue(4);
    q.addToQueue(5);
 
    q.addToQueue(6); // Невозможно поставить в очередь, потому что firstElementPos == 0 && lastElementPos == CAPACITY - 1
 
    int elem = q.takeFromQueue();
 
    if (elem != NULL)
        std::cout << "Deleted Element is " << elem << std::endl;
 
    q.printQueueSize();
 
    q.addToQueue(7);
 
    q.printQueueSize();
 
    q.addToQueue(8); // Невозможно поставить в очередь, потому что firstElementPos == lastElementPos + 1
 
    // ================================================================== //
    std::cout << "// ---------- Сopy constructor ---------- //" << std::endl;
    // ================================================================== //
 
    Queue<int, 5> q1{ q }; // Использование конструктора копирования
 
    q1.printQueueSize();
 
    // ================================================================== //
    std::cout << "// ---------- Assignment operator ---------- //" << std::endl;
    // ================================================================== //
 
    Queue<int, 5> b;
 
    b.printQueueSize();
 
    b.addToQueue(0);
    b.addToQueue(9);
    b.addToQueue(8);
    b.addToQueue(7);
    b.addToQueue(6);
 
    b = q; // Использование оператора присваивания копирования
 
    b.printQueueSize();
 
    return 0;
}
0
Лучшие ответы (1)
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
07.09.2024, 14:45
Ответы с готовыми решениями:

Циклическая и не циклическая очередь
Разработать программу, реализующую операции над не циклической или циклической очередью с помощью статического массива записей

Шаблонная очередь,с 2 типами аргументов
Не могу понять как можно сделать шаблонную очередь, аргументами которой могут быть числа и строки,если делать через шаблонные классы,то они...

Шаблонная двусвязная очередь. Перегрузка операторов [], + и -
Есть код шаблонного двусвязного списка с перегруженными операторами. Необходимо сделать шаблонный дек и перегрузить оператор индексации,...

5
184 / 72 / 35
Регистрация: 09.05.2022
Сообщений: 387
08.09.2024, 16:47
Статическую аллокацию ты уже сделал, массив queueOfElements[CAPACITY] - это и есть статика. Просто убери слово static, оно тут не нужно.

Уничтожать элементы при извлечении? Просто вызывай деструктор: queueOfElements[firstElementPos].~T();

NULL для примитивных типов? Серьёзно? Используй std::optional, если так неймётся.

Конструктор копирования норм, но оператор присваивания можно выкинуть. Правило трёх (или пяти) - слышал о таком?

Короче, почитай про RAII и семантику перемещения. И да, static члены класса тут вообще ни при чём. Не забудь протестировать на разных типах, а то потом будешь локти кусать.
1
0 / 0 / 0
Регистрация: 07.09.2024
Сообщений: 3
08.09.2024, 19:19  [ТС]
Спасибо за ответ!
Цитата Сообщение от karlhildekruger Посмотреть сообщение
Просто вызывай деструктор: queueOfElements[firstElementPos].~T();
Попробовал сделать так:
C++
1
2
element = queueOfElements[firstElementPos]; // Запись первого элемента из очереди
queueOfElements[firstElementPos].~T();
Ошибок не выдало, но в массиве после удаления все так же остается тот же элемент, ничего нее изменилось, может я что-то делаю не так?

Правило пяти слышал, но тут почему-то просят убрать оператор присваивания.
0
Вездепух
Эксперт CЭксперт С++
 Аватар для TheCalligrapher
12933 / 6801 / 1820
Регистрация: 18.10.2014
Сообщений: 17,213
08.09.2024, 19:27
Цитата Сообщение от kobru Посмотреть сообщение
Ошибок не выдало, но в массиве после удаления все так же остается тот же элемент, ничего нее изменилось, может я что-то делаю не так?
И что из этого? Что по вашим ожиданиям должно было произойти? В памяти должна была образоваться черная дыра?
0
0 / 0 / 0
Регистрация: 07.09.2024
Сообщений: 3
08.09.2024, 19:50  [ТС]
Я хотел узнать, есть ли способ уничтожать элементы при извлечении кроме как присвоить им новое значение, например, какое-то конкретное, типо "0" или варианта сдвига всей очереди
0
Вездепух
Эксперт CЭксперт С++
 Аватар для TheCalligrapher
12933 / 6801 / 1820
Регистрация: 18.10.2014
Сообщений: 17,213
08.09.2024, 23:20
Лучший ответ Сообщение было отмечено kobru как решение

Решение

Цитата Сообщение от kobru Посмотреть сообщение
но тут почему-то просят убрать оператор присваивания.
Если вы пойдете пор пути queueOfElements[firstElementPos].~T(), то оператор присваивания убирать нельзя. Все специальные методы придется обязательно писать руками: и деструктор, и все конструкторы копирования/перемещения, и все операторы присваивания.

Хотя при этом надо заметить, что если у типа T нет оператора присваивания, то и у вашего класса очереди не может быть соответствующего присваивания тоже.

Однако лучше было бы использовать std::optional<T> (C++20) в качестве элемента массива. Тогда сработало бы Правло Нуля, т.е. никаких специальные методов писать руками не нужно было бы.

Добавлено через 4 минуты
Цитата Сообщение от kobru Посмотреть сообщение
Я хотел узнать, есть ли способ уничтожать элементы при извлечении
Невозможно "уничтожить" элемент массива. Как вы себе это представляете?

Цитата Сообщение от kobru Посмотреть сообщение
кроме как присвоить им новое начение, например, какое-то конкретное, типо "0"
А смысл? Чем это "новое значение" лучше остающегося в элементе в качестве мусора "старого значения"? Мусор имеет смысл затирать, если там могут хранится чувствительные данные ("пароли" и т.п.). Но у вас задача не об этом.

Цитата Сообщение от kobru Посмотреть сообщение
или варианта сдвига всей очереди
Вся ваша структура данных как раз и ориентирована на то, чтобы ничего никуда не сдвигать. Сдвиг - тяжелая операция. Весь смысл такой организации циклической очереди как раз и сводится к тому, чтобы избежать сдвигов.
1
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
08.09.2024, 23:20
Помогаю со студенческими работами здесь

Циклическая очередь
Создать класс типа - циклическая очередь. Функции-члены получают элемент и вставляют элемент.

Циклическая очередь
Нужно написать шаблон класса, описывающие циклическую, представленную динамическим массивом хранимых объектов. Размерность очереди -...

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

Циклическая очередь
Всем привет, надо создать класс с циклической очередью целых. Сделать очередь длиной 100 целых. В функцию main() включите краткую...

Циклическая очередь на основе массива
помогите написать код для циклической очереди на основе массива:)


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

Или воспользуйтесь поиском по форуму:
6
Ответ Создать тему
Новые блоги и статьи
Инструменты COM: Сохранение данный из VARIANT в файл и загрузка из файла в VARIANT
bedvit 28.01.2026
Сохранение базовых типов COM и массивов (одномерных или двухмерных) любой вложенности (деревья) в файл, с возможностью выбора алгоритмов сжатия и шифрования. Часть библиотеки BedvitCOM Использованы. . .
Киев стоит - украинская песня
zorxor 28.01.2026
wfWdiRqdTxc О Господи, Вечный, Ты . . . Я помоги, Бесконечный. . . Я прошу Ты. . . Я погибаю, спаси. . . Я прошу Тебя Вечный. . .
Загрузка PNG с альфа-каналом на SDL3 для Android: с помощью SDL_LoadPNG (без SDL3_image)
8Observer8 28.01.2026
Содержание блога SDL3 имеет собственные средства для загрузки и отображения PNG-файлов с альфа-каналом и базовой работы с ними. В этой инструкции используется функция SDL_LoadPNG(), которая. . .
Загрузка PNG с альфа-каналом на SDL3 для Android: с помощью SDL3_image
8Observer8 27.01.2026
Содержание блога SDL3_image - это библиотека для загрузки и работы с изображениями. Эта пошаговая инструкция покажет, как загрузить и вывести на экран смартфона картинку с альфа-каналом, то есть с. . .
влияние грибов на сукцессию
anaschu 26.01.2026
Бифуркационные изменения массы гриба происходят тогда, когда мы уменьшаем массу компоста в 10 раз, а скорость прироста биомассы уменьшаем в три раза. Скорость прироста биомассы может уменьшаться за. . .
Воспроизведение звукового файла с помощью SDL3_mixer при касании экрана Android
8Observer8 26.01.2026
Содержание блога SDL3_mixer - это библиотека я для воспроизведения аудио. В отличие от инструкции по добавлению текста код по проигрыванию звука уже содержится в шаблоне примера. Нужно только. . .
Установка Android SDK, NDK, JDK, CMake и т.д.
8Observer8 25.01.2026
Содержание блога Перейдите по ссылке: https:/ / developer. android. com/ studio и в самом низу страницы кликните по архиву "commandlinetools-win-xxxxxx_latest. zip" Извлеките архив и вы увидите. . .
Вывод текста со шрифтом TTF на Android с помощью библиотеки SDL3_ttf
8Observer8 25.01.2026
Содержание блога Если у вас не установлены Android SDK, NDK, JDK, и т. д. то сделайте это по следующей инструкции: Установка Android SDK, NDK, JDK, CMake и т. д. Сборка примера Скачайте. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru