Я кодирую простой шаблонный кольцевой буфер:
template <typename T, size_t N>
class CircularBuffer {
T _buf[N];
T *_data;
size_t _head;
size_t _count;
size_t _capacity;
CircularBuffer():
_data(nullptr),
_head(0),
_count(0),
_capacity(N) {}
protected:
T* buffer() {
if (_count <= N) return &_buf;
else return _data;
}
public:
T& operator[](size_t i) {
size_t j = i % _count;
j = (_head + j) % _capacity;
return buffer()[j];
}
T& push_back(const T& o) {
if (_count == _capacity) {
dynamically_allocate_data();
}
size_t j = (_head + _count++) % _capcity;
buffer()[j] = o;
}
T pop_front() {
size_t old_head = _head;
_head = (_head + 1) % _capacity;
return buffer()[old_head];
}
};
Это урезано от реальной вещи, но это не за горами, и вы поняли идею.Это позволяет избежать выделения памяти для буферов менее чем N
элементов.
Проблема заключается в том, что это не работает для T
, которые не имеют конструкторов по умолчанию.Я мог бы предоставить конструктор для CircularBuffer
- ala std::vector
s -, который принимает T
для заполнения пустого буфера, но я не уверен, как на самом деле реализовать это, не вызывая неявно T
Конструктор по умолчанию (возможно, не существующий).
В ответах на аналогичные вопросы предлагается использовать std::vector
или размещение нового в массиве void*
, но в этом случае это не относится, поскольку весь смысл заключается вИзбегайте динамического выделения памяти во внутреннем цикле.
Как я могу построить этот класс для T
без конструкторов по умолчанию?(Или, альтернативно, есть ли другая схема, которая позволит избежать необходимости создания пустого T
в буфере для начала?)