C++ 模板化环形缓冲区实现:如何单独声明和初始化它?

C++ templated ring buffer implementation: how to declare and initialize it separately?

我在 github 上发现了 this 带有互斥锁的环形缓冲区的实现。我贴上代码给你看:

#include <cstdio>

#include <memory>
#include <mutex>

template <class T>
class circular_buffer {
public:
    explicit circular_buffer(size_t size) :
        buf_(std::unique_ptr<T[]>(new T[size])),
        max_size_(size)
    {

    }

void put(T item)
{
    std::lock_guard<std::mutex> lock(mutex_);

    buf_[head_] = item;

    if(full_)
    {
        tail_ = (tail_ + 1) % max_size_;
    }

    head_ = (head_ + 1) % max_size_;

    full_ = head_ == tail_;
}

T get()
{
    std::lock_guard<std::mutex> lock(mutex_);

    if(empty())
    {
        return T();
    }

    //Read data and advance the tail (we now have a free space)
    auto val = buf_[tail_];
    full_ = false;
    tail_ = (tail_ + 1) % max_size_;

    return val;
}

void reset()
{
    std::lock_guard<std::mutex> lock(mutex_);
    head_ = tail_;
    full_ = false;
}

bool empty() const
{
    //if head and tail are equal, we are empty
    return (!full_ && (head_ == tail_));
}

bool full() const
{
    //If tail is ahead the head by 1, we are full
    return full_;
}

size_t capacity() const
{
    return max_size_;
}

size_t size() const
{
    size_t size = max_size_;

    if(!full_)
    {
        if(head_ >= tail_)
        {
            size = head_ - tail_;
        }
        else
        {
            size = max_size_ + head_ - tail_;
        }
    }

    return size;
}

private:
    std::mutex mutex_;
    std::unique_ptr<T[]> buf_;
    size_t head_ = 0;
    size_t tail_ = 0;
    const size_t max_size_;
    bool full_ = 0;
};

int main(void)
{
circular_buffer<uint32_t> circle(10);
printf("\n === CPP Circular buffer check ===\n");
printf("Size: %zu, Capacity: %zu\n", circle.size(), circle.capacity());

uint32_t x = 1;
printf("Put 1, val: %d\n", x);
circle.put(x);

x = circle.get();
printf("Popped: %d\n", x);

printf("Empty: %d\n", circle.empty());

printf("Adding %zu values\n", circle.capacity() - 1);
for(uint32_t i = 0; i < circle.capacity() - 1; i++)
{
    circle.put(i);
}

circle.reset();

printf("Full: %d\n", circle.full());

printf("Adding %zu values\n", circle.capacity());
for(uint32_t i = 0; i < circle.capacity(); i++)
{
    circle.put(i);
}

printf("Full: %d\n", circle.full());

printf("Reading back values: ");
while(!circle.empty())
{
    printf("%u ", circle.get());
}
printf("\n");

printf("Adding 15 values\n");
for(uint32_t i = 0; i < circle.size() + 5; i++)
{
    circle.put(i);
}

printf("Full: %d\n", circle.full());

printf("Reading back values: ");
while(!circle.empty())
{
    printf("%u ", circle.get());
}
printf("\n");

printf("Empty: %d\n", circle.empty());
printf("Full: %d\n", circle.full());

return 0;
}

在代码块的末尾,您可以找到带有示例的主函数。在那里,队列用 space 初始化为 10 个元素,如

circular_buffer<uint32_t> circle(10);

因为我想将其中一个环形缓冲区用作另一个 class 中的对象进行测试,我一直在尝试声明缓冲区,然后使用指示大小的变量对其进行初始化。这只是我想要完成的一个例子,就像通常在 java:

中所做的那样
int size = 20;
circular_buffer<uint16_t> ring;
ring = new circular_buffer<uint16_t>(size);

到目前为止我试过的所有东西都不编译。在 C++ 中使用模板化 class 这可能吗?

谢谢。

您已在具有自动存储期限的堆栈上声明 ring。这不是一个指针:

circular_buffer<uint16_t> ring;

但随后您尝试使用 new 在堆上动态构造它,它期望 ring 是指针类型(例如 circular_buffer<uint16_t>* ring;

你的示例中不需要动态分配,直接构造即可:

int size = 20;
circular_buffer<uint16_t> ring{size};