繁体   English   中英

C++ 简单的循环缓冲区队列

[英]C++ Simple circular-buffer Queue

我使用数组实现了一个队列并将其视为循环缓冲区。 _tail指向下一个要读取的元素, _head指向下一个要写入的元素:

template<int SIZE>
class Q {

bool push(const int item){
    if(false == isFull()){
        _q[_head] = item;
        _head = ++_head % SIZE;
        return true;
    }

    return false;
}

bool pop(int& toReturn){
    if(false == isEmpty()){
        toReturn = _q[_tail];
        _tail = ++_tail % SIZE;  
        return true;
    }

    return false;
}

private:

    std::array<int, SIZE> _q;
    std::atomic<int> _head;
    std::atomic<int> _tail;
};

但是,我的isFull()isEmpty()逻辑中有一个错误,由以下问题确定:

当队列最初为空时, _tail_head都将指向_q[0]

当我再次写入_q[0]_q[1]_q[2]q[3]时, _tail_head将指向相同的内容,所以很明显我不能使用_tail == _head来确定满/空。

实现isEmpty()isFull()逻辑的最简单方法是什么? 我不确定在读取队列项后是否应该编写“空白”枚举?

在类中声明一个数据成员(计数器),用于计算队列中的项目数。 递增(推)并递减(弹出)。 当它为(0)时,队列为空

如果您愿意将队列的有效大小减少一个元素,那么逻辑相对简单:

  • headtail相同时,队列为空。
  • tail递增1时,使用环绕生成head ,队列已满。

这使得不可能插入作为“哨兵”的第N个元素。 因此,对于N元素队列,您需要分配N + 1个元素的数组,并在处理环绕的所有表达式中使用(SIZE+1)

std::array<int,SIZE+1> _q;

实施说明:

这两行

_head = ++_head % SIZE;
_tail = ++_tail % SIZE;  

具有未定义的行为,因为编译器可以灵活地应用在赋值结束之前或之后递增_head_tail副作用。 如果编译器选择在赋值后应用副作用,则不会发生环绕效果。

由于您根本不需要复合赋值,因此修复很简单:

_head = (_head+1) % SIZE;
_tail = (_tail+1) % SIZE;  

如何改变实现有点像

将头部的定义从“ _head points to the next element to write into: ”改为
_head points to latest element added

然后isFull()可以

bool isFull()
{
    if((_head + 1) % SIZE == _tail)
        return true;

    return false;
}

并且isEmpty可以

bool isEmpty()
{
    if(_head == _tail)
        return true;

    return false;
}

pop()将相同但更改push()并且不要忘记将_head_tail初始化为-1

bool push(const int item){
    if(false == isFull()){
        if(_head == -1)    //If adding the first element,
            _tail = 0;     // tail will point to it as it was inititiallty 0
        _head = ++_head % SIZE;
         _q[_head] = item;
        return true;
    }

    return false;
}

由于您使用模数来计算数组的索引,因此保留每次读取和写入的运行计数可以简化逻辑。

改变这样的实现......

bool push(const int item){
    if(false == isFull()){
        _q[_head % SIZE] = item;
        ++_head;
        return true;
    }

    return false;
}

bool pop(int& toReturn){
    if(false == isEmpty()){
        toReturn = _q[_tail % SIZE];
        ++_tail;  
        return true;
    }

    return false;
}

并使用这些......

bool isFull()
{
    return _head - _tail == SIZE;
}

bool isEmpty()
{
    if (_head == _tail)
    {
        _head = _tail = 0;
        return true;
    }

    return false;
}

如果你需要一个全功能的环形缓冲区,试试这个:

#pragma once
#include <vector>
#include <stdexcept>
#include <new>
#include <utility>
#include <cstring>
#include <cassert>

#if defined(_MSC_VER)
    #pragma warning(push)
    #pragma warning(disable: 26495) // uninitialized member t at TU::TU()
#endif
#if defined(__llvm__)
    #pragma clang diagnostic push
    #pragma clang diagnostic ignored "-Wdangling-else"
#endif

template<typename T, typename Alloc = std::allocator<T>>
class ring_buffer
{
    union TU
    {
        T t;
        TU()  {}
        ~TU() {}
    };
    using vec_t = std::vector<TU, typename std::allocator_traits<Alloc>::template rebind_alloc<TU>>;
    using it_t  = typename vec_t::iterator;
public:
    struct iterator;
    struct const_iterator
    {
                        const_iterator();
                        const_iterator( const_iterator const &it );
        const_iterator &operator +=( std::ptrdiff_t offset );
        const_iterator &operator -=( std::ptrdiff_t offset );
        const_iterator &operator  =( const_iterator const &it );
        bool            operator ==( const_iterator const &it ) const;
        bool            operator !=( const_iterator const &it ) const;
        bool            operator  <( const_iterator const &it ) const;
        bool            operator <=( const_iterator const &it ) const;
        bool            operator  >( const_iterator const &it ) const;
        bool            operator >=( const_iterator const &it ) const;
        const_iterator  operator  +( std::ptrdiff_t offset ) const;
        const_iterator  operator  -( std::ptrdiff_t offset ) const;
        T const        &operator  *() const;
        const_iterator &operator ++();
        const_iterator &operator --();
        const_iterator  operator ++( int );
        const_iterator  operator --( int );
        T const        &operator []( std::ptrdiff_t offset ) const;
        T const        &at( std::ptrdiff_t offset ) const;
    private:
        friend class ring_buffer;
                        const_iterator( ring_buffer &ring, it_t it );
        std::ptrdiff_t  idx() const;
        template<bool THROW = false>
        it_t         offset_it( std::ptrdiff_t offset ) const;
        ring_buffer *m_ring;
        it_t         m_it;
    };
    struct iterator : public const_iterator
    {
                 iterator();
                 iterator( iterator const &it );
        iterator &operator +=( std::ptrdiff_t offset );
        iterator &operator -=( std::ptrdiff_t offset );
        iterator &operator  =( iterator const &it );
        iterator  operator  +( std::ptrdiff_t offset ) const;
        iterator  operator  -( std::ptrdiff_t offset ) const;
        T        &operator  *() const;
        iterator &operator ++();
        iterator &operator --();
        iterator  operator ++( int );
        iterator  operator --( int );
        T        &operator []( std::ptrdiff_t offset ) const;
        T        &at(          std::ptrdiff_t offset ) const;
    private:
                  iterator( ring_buffer &ring, it_t it );
        explicit  iterator( const_iterator const &it );
        friend class ring_buffer;
    };
                    ring_buffer( std::size_t cap );
                    ring_buffer( ring_buffer const &other );
                    ~ring_buffer();
    T              &operator []( std::size_t offset );
    T              &at( std::size_t offset );
    T              &front() const;
    iterator        begin() const;
    iterator        end() const;
    const_iterator  cbegin() const;
    const_iterator  cend() const;
    void            pop_front();
    template<typename ... Args>
    T              &emplace_back( Args &&...args );
    T              &push_back( T const &other );
    T              &push_back( T &&other );
    bool            full() const;
    std::size_t     size() const;
    void            capacity( std::size_t newCap );
private:
    vec_t  m_ring;
    it_t   m_read, m_write;
    size_t m_size, m_capacity;
};

template<typename T, typename Alloc>
inline
std::ptrdiff_t ring_buffer<T, Alloc>::const_iterator::idx() const
{
    if( m_it >= m_ring->m_read )
    {
        assert(   m_ring->m_read  <= m_ring->m_write && m_it <= m_ring->m_write
               || m_ring->m_write <  m_ring->m_read   & m_it >= m_ring->m_ring.begin() && m_it <= m_ring->m_write);
        return m_it - m_ring->m_read;
    }
    else
    {
        assert(m_it >= m_ring->m_ring.begin() && m_it <= m_ring->m_write);
        return (m_it - m_ring->m_ring.begin()) + (m_ring->m_ring.end() - m_ring->m_read);
    }
}

template<typename T, typename Alloc>
template<bool THROW>
inline
typename ring_buffer<T, Alloc>::it_t ring_buffer<T, Alloc>::const_iterator::offset_it( std::ptrdiff_t offset ) const
{
    using namespace std;
    ptrdiff_t rel;
    static
    char const outOfRangeStr[] = "ring-buffer access out of range";
    if( m_ring->m_read <= m_ring->m_write )
    {
        rel = m_it - m_ring->m_read + offset;
        if constexpr( !THROW )
            assert(rel >= 0 && rel <= m_ring->m_write - m_ring->m_read);
        else
            if( rel < 0 || rel > m_ring->m_write - m_ring->m_read )
                throw out_of_range( outOfRangeStr );
        return m_it + offset;
    }
    if( offset >= 0 )
    {
        if( m_it >= m_ring->m_read )
        {
            rel = m_it - m_ring->m_read + offset;
            if( rel < m_ring->m_ring.end() - m_ring->m_read )
                return m_it + rel;
            rel -= m_ring->m_ring.end() - m_ring->m_read;
            if constexpr( !THROW )
                assert(rel <= m_ring->m_write - m_ring->m_ring.begin());
            else
                if( rel > m_ring->m_write - m_ring->m_ring.begin() )
                    throw out_of_range( outOfRangeStr );
            return m_ring->m_ring.begin() + rel;
        }
        if constexpr( !THROW )
            assert(m_it - m_ring->m_ring.begin() + offset <= m_ring->m_write - m_ring->m_ring.begin());
        else
            if( m_it - m_ring->m_ring.begin() + offset > m_ring->m_write - m_ring->m_ring.begin() )
                throw out_of_range( outOfRangeStr );
        return m_it + offset;
    }
    if( m_it >= m_ring->m_read )
    {
        rel = m_it - m_ring->m_read + offset;
        if constexpr( !THROW )
            assert(rel >= 0);
        else
            if( rel < 0 )
                throw out_of_range( outOfRangeStr );
        return m_it + offset;
    }
    rel = m_it - m_ring->m_ring.begin() + offset;
    if( rel >= 0 )
        return m_it + rel;
    rel += m_it - m_ring->m_ring.begin();
    if constexpr( !THROW )
        assert(m_ring->m_ring.end() - m_ring->m_read >= -rel);
    else
        if( m_ring->m_ring.end() - m_ring->m_read < -rel )
            throw out_of_range( outOfRangeStr );
    return m_ring->m_ring.end() + rel;
}

template<typename T, typename Alloc>
inline
ring_buffer<T, Alloc>::const_iterator::const_iterator()
#if !defined(NDEBUG)
    : m_ring( nullptr )
#endif
{
}

template<typename T, typename Alloc>
inline
ring_buffer<T, Alloc>::const_iterator::const_iterator( const_iterator const &it ) :
    m_ring( it.m_ring ),
    m_it( it.m_it )
{
}

template<typename T, typename Alloc>
inline
ring_buffer<T, Alloc>::const_iterator::const_iterator( ring_buffer &ring, it_t it ) :
    m_ring( &ring ),
    m_it( it )
{
}

template<typename T, typename Alloc>
inline
typename ring_buffer<T, Alloc>::const_iterator &ring_buffer<T, Alloc>::const_iterator::operator +=( std::ptrdiff_t offset )
{
    m_it = offset_it( offset );
    return *this;
}

template<typename T, typename Alloc>
inline
typename ring_buffer<T, Alloc>::const_iterator &ring_buffer<T, Alloc>::const_iterator::operator -=( std::ptrdiff_t offset )
{
    m_it = offset_it( -offset );
    return *this;
}

template<typename T, typename Alloc>
inline
typename ring_buffer<T, Alloc>::const_iterator &ring_buffer<T, Alloc>::const_iterator::operator =( const_iterator const &it )
{
    m_ring = it.m_ring;
    m_it   = it.m_it;
    return *this;
}

template<typename T, typename Alloc>
inline
bool ring_buffer<T, Alloc>::const_iterator::operator ==( const_iterator const &it ) const
{
    assert(m_ring == it.m_ring);
    return m_it == it.m_it;
}

template<typename T, typename Alloc>
inline
bool ring_buffer<T, Alloc>::const_iterator::operator !=( const_iterator const &it ) const
{
    assert(m_ring == it.m_ring);
    return m_it != it.m_it;
}

template<typename T, typename Alloc>
inline
bool ring_buffer<T, Alloc>::const_iterator::operator  <( const_iterator const &it ) const
{
    assert(m_ring == it.m_ring);
    return idx() < it.idx();
}

template<typename T, typename Alloc>
inline
bool ring_buffer<T, Alloc>::const_iterator::operator <=( const_iterator const &it ) const
{
    assert(m_ring == it.m_ring);
    return idx() <= it.idx();
}

template<typename T, typename Alloc>
inline
bool ring_buffer<T, Alloc>::const_iterator::operator >( const_iterator const &it ) const
{
    assert(m_ring == it.m_ring);
    return idx() > it.idx();
}

template<typename T, typename Alloc>
inline
bool ring_buffer<T, Alloc>::const_iterator::operator >=( const_iterator const &it ) const
{
    assert(m_ring == it.m_ring);
    return idx() >= it.idx();
}

template<typename T, typename Alloc>
inline
typename ring_buffer<T, Alloc>::const_iterator ring_buffer<T, Alloc>::const_iterator::operator +( std::ptrdiff_t offset ) const
{
    return const_iterator( *m_ring, offset_it( offset ) );
}

template<typename T, typename Alloc>
inline
typename ring_buffer<T, Alloc>::const_iterator ring_buffer<T, Alloc>::const_iterator::operator -( std::ptrdiff_t offset ) const
{
    return const_iterator( *m_ring, offset_it( -offset ) );
}

template<typename T, typename Alloc>
inline
T const &ring_buffer<T, Alloc>::const_iterator::operator *() const
{
    assert(idx() < (std::ptrdiff_t)m_ring->m_size);
    return m_it->t;
}

template<typename T, typename Alloc>
inline
typename ring_buffer<T, Alloc>::const_iterator &ring_buffer<T, Alloc>::const_iterator::operator ++()
{
    m_it = offset_it( 1 );
    return *this;
}

template<typename T, typename Alloc>
inline
typename ring_buffer<T, Alloc>::const_iterator &ring_buffer<T, Alloc>::const_iterator::operator --()
{
    m_it = offset_it( -1 );
    return *this;
}

template<typename T, typename Alloc>
inline
typename ring_buffer<T, Alloc>::const_iterator ring_buffer<T, Alloc>::const_iterator::operator ++( int )
{
    const_iterator ret( *this );
    m_it = offset_it( 1 );
    return ret;
}

template<typename T, typename Alloc>
inline
typename ring_buffer<T, Alloc>::const_iterator ring_buffer<T, Alloc>::const_iterator::operator --( int )
{
    const_iterator ret( *this );
    m_it = offset_it( -1 );
    return ret;
}

template<typename T, typename Alloc>
inline
T const &ring_buffer<T, Alloc>::const_iterator::operator []( std::ptrdiff_t offset ) const
{
    assert(offset_it( offset ) != m_ring->m_write);
    return offset_it( offset )->t;
}

template<typename T, typename Alloc>
inline
T const &ring_buffer<T, Alloc>::const_iterator::at( std::ptrdiff_t offset ) const
{
    assert(offset_it( offset ) != m_ring->m_write);
    return offset_it<true>( offset )->t;
}

template<typename T, typename Alloc>
inline
ring_buffer<T, Alloc>::iterator::iterator() :
    const_iterator()
{
}

template<typename T, typename Alloc>
inline
ring_buffer<T, Alloc>::iterator::iterator( iterator const &it ) :
    const_iterator( it )
{
}

template<typename T, typename Alloc>
inline
ring_buffer<T, Alloc>::iterator::iterator( ring_buffer &ring, it_t it ) :
    const_iterator( ring, it )
{
}

template<typename T, typename Alloc>
inline
ring_buffer<T, Alloc>::iterator::iterator( const_iterator const &it ) :
    const_iterator( it )
{
}

template<typename T, typename Alloc>
inline
typename ring_buffer<T, Alloc>::iterator &ring_buffer<T, Alloc>::iterator::operator +=( std::ptrdiff_t offset )
{
    return (iterator &)const_iterator::operator +=( offset );
}

template<typename T, typename Alloc>
inline
typename ring_buffer<T, Alloc>::iterator &ring_buffer<T, Alloc>::iterator::operator -=( std::ptrdiff_t offset )
{
    return (iterator &)const_iterator::operator -=( -offset );
}

template<typename T, typename Alloc>
inline
typename ring_buffer<T, Alloc>::iterator &ring_buffer<T, Alloc>::iterator::operator =( iterator const &it )
{
    return (iterator &)const_iterator::operator =( it );
}

template<typename T, typename Alloc>
inline
typename ring_buffer<T, Alloc>::iterator ring_buffer<T, Alloc>::iterator::operator +( std::ptrdiff_t offset ) const
{
    return (iterator)const_iterator::operator +( offset );
}

template<typename T, typename Alloc>
inline
typename ring_buffer<T, Alloc>::iterator ring_buffer<T, Alloc>::iterator::operator -( std::ptrdiff_t offset ) const
{
    return (iterator)const_iterator::operator -( offset );
}

template<typename T, typename Alloc>
inline
T &ring_buffer<T, Alloc>::iterator::operator *() const
{
    return (T &)const_iterator::operator *();
}

template<typename T, typename Alloc>
inline
typename ring_buffer<T, Alloc>::iterator &ring_buffer<T, Alloc>::iterator::operator ++()
{
    return (iterator &)const_iterator::operator ++();
}

template<typename T, typename Alloc>
inline
typename ring_buffer<T, Alloc>::iterator &ring_buffer<T, Alloc>::iterator::operator --()
{
    return (iterator &)const_iterator::operator --();
}

template<typename T, typename Alloc>
inline
typename ring_buffer<T, Alloc>::iterator ring_buffer<T, Alloc>::iterator::operator ++( int )
{
    return (iterator)const_iterator::operator ++( 1 );
}

template<typename T, typename Alloc>
inline
typename ring_buffer<T, Alloc>::iterator ring_buffer<T, Alloc>::iterator::operator --( int )
{
    return (iterator)const_iterator::operator --( 1 );
}

template<typename T, typename Alloc>
inline
T &ring_buffer<T, Alloc>::iterator::operator []( std::ptrdiff_t offset ) const
{
    return (T &)const_iterator::operator []( offset );
}

template<typename T, typename Alloc>
inline
T &ring_buffer<T, Alloc>::iterator::at( std::ptrdiff_t offset ) const
{
    return (T &)const_iterator::at( offset );
}

template<typename T, typename Alloc>
ring_buffer<T, Alloc>::ring_buffer( std::size_t cap ) :
    m_ring( cap + 1 ),
    m_read( m_ring.begin() ),
    m_write( m_ring.begin() ),
    m_size( 0 ),
    m_capacity( cap )
{
}

template<typename T, typename Alloc>
ring_buffer<T, Alloc>::ring_buffer( ring_buffer const &other ) :
    m_ring( other.m_capacity + 1 ),
    m_size( other.m_size ),
    m_capacity( other.m_capacity ),
    m_read( m_ring.begin() ),
    m_write( m_ring.begin() + m_size )
{
    it_t write = m_read;
    try
    {
        for( TU const &tu : other.m_ring )
            new( (void *)&*write++ )T( tu.t );
    }
    // if an exception occurs, destroy the objects which we've copied so far
    catch( ... )
    {
        for( it_t begin = m_read; write > begin; (--write)->t.~T() );
        throw;
    }
}

template<typename T, typename Alloc>
ring_buffer<T, Alloc>::~ring_buffer()
{
    auto destrRange = []( it_t destr, it_t end )
    {
        for( ; destr != end; destr++->t.~T() );
    };
    if( m_read <= m_write )
    {
        destrRange( m_read, m_write );
        return;
    }
    destrRange( m_read,  m_ring.end() );
    destrRange( m_ring.begin(), m_write );
}

template<typename T, typename Alloc>
inline
T &ring_buffer<T, Alloc>::operator []( std::size_t offset )
{
    using namespace std;
    assert(offset < m_size);
    if( m_write >= m_read )
    {
        assert((size_t)(m_ring.end() - m_ring.begin()) > offset);
        return m_read[offset].t;
    }
    if( offset < (size_t)(m_ring.end() - m_read) )
        return m_read[offset].t;
    offset -= m_ring.end() - m_read;
    assert((size_t)(m_write - m_ring.begin()) > offset);
    return m_ring[offset].t;
}

template<typename T, typename Alloc>
inline
T &ring_buffer<T, Alloc>::at( std::size_t offset )
{
    using namespace std;
    if( m_size == 0 )
        throw logic_error( "ring-buffer empty" );
    if( m_write >= m_read )
        if( offset < (size_t)(m_write - m_read) )
            return m_read[offset].t;
        else
            throw out_of_range( "ring-buffer index too large" );
    if( offset < (size_t)(m_ring.end() - m_read) )
        return m_read[offset].t;
    if( (offset -= m_ring.end() - m_read) >= (size_t)(m_write - m_ring.begin()) )
        throw out_of_range( "ring-buffer index too large" );
    return m_ring[offset].t;
}

template<typename T, typename Alloc>
inline
T &ring_buffer<T, Alloc>::front() const
{
    assert(m_size);
    return m_read->t;
}

template<typename T, typename Alloc>
inline
typename ring_buffer<T, Alloc>::iterator ring_buffer<T, Alloc>::begin() const
{
    return iterator( *(ring_buffer *)this, m_read );
}

template<typename T, typename Alloc>
inline
typename ring_buffer<T, Alloc>::iterator ring_buffer<T, Alloc>::end() const
{
    return iterator( *(ring_buffer *)this, m_write );
}

template<typename T, typename Alloc>
inline
typename ring_buffer<T, Alloc>::const_iterator ring_buffer<T, Alloc>::cbegin() const
{
    return const_iterator( *(ring_buffer *)this, m_read );
}

template<typename T, typename Alloc>
inline
typename ring_buffer<T, Alloc>::const_iterator ring_buffer<T, Alloc>::cend() const
{
    return const_iterator( *(ring_buffer *)this, m_write );
}

template<typename T, typename Alloc>
inline
void ring_buffer<T, Alloc>::pop_front()
{
    assert(m_size);
    m_read->t.~T();
    if( ++m_read == m_ring.end() )
        m_read = m_ring.begin();
    --m_size;
}

template<typename T, typename Alloc>
template<typename ... Args>
T &ring_buffer<T, Alloc>::emplace_back( Args &&...args )
{
    using namespace std;
    assert(m_capacity);
    if( m_size == m_capacity )
        pop_front();
    T &t = m_write->t;
    new( (void *)&t )T( forward<Args>( args ) ... );
    if( ++m_write == m_ring.end() )
        m_write = m_ring.begin();
    ++m_size;
    return t;
}

template<typename T, typename Alloc>
T &ring_buffer<T, Alloc>::push_back( T const &other )
{
    using namespace std;
    assert(m_capacity);
    if( m_size == m_capacity )
        pop_front();
    T &t = m_write->t;
    new( (void *)&t )T( other );
    if( ++m_write == m_ring.end() )
        m_write = m_ring.begin();
    ++m_size;
    return t;
}

template<typename T, typename Alloc>
T &ring_buffer<T, Alloc>::push_back( T &&other )
{
    using namespace std;
    assert(m_capacity);
    if( m_size == m_capacity )
        pop_front();
    T &t = m_write->t;
    new( (void *)&t )T( move( other ) );
    if( ++m_write == m_ring.end() )
        m_write = m_ring.begin();
    ++m_size;
    return t;
}

template<typename T, typename Alloc>
inline
std::size_t ring_buffer<T, Alloc>::size() const
{
    return m_size;
}

template<typename T, typename Alloc>
inline
bool ring_buffer<T, Alloc>::full() const
{
    return m_size == m_capacity;
}

template<typename T, typename Alloc>
void ring_buffer<T, Alloc>::capacity( std::size_t newCap )
{
    using namespace std;
    if( newCap < m_size )
        throw invalid_argument( "new ring-buffer size too small" );
    vec_t newRing( newCap + 1 );
    it_t  to = newRing.begin();
    auto moveRange = [&to]( it_t from, it_t fromEnd )
    {
        for( ; from != fromEnd; ++from, ++to )
            new( (void *)&*to )T( move( from->t ) );
    };
    auto destrRange = []( it_t destr, it_t end )
    {
        for( ; destr != end; (--destr)->t.~T() );
    };
    try
    {
        // destroy after copying / moving completely because whe might copy only if there isn't
        // move-constructor and have an exception; so the whole thing becomes transactional
        if( m_read <= m_write )
            moveRange(  m_read,         m_write        ),
            destrRange( m_write,        m_read         );
        else
            moveRange(  m_read,         m_ring.end()   ),
            moveRange(  m_ring.begin(), m_write        ),
            destrRange( m_write,        m_ring.begin() ),
            destrRange( m_ring.end(),   m_read         );
    }
    // if there's an exception, the objects haven't been moved but copied;
    // so we can destroy the objects in the destination-vector created so far
    catch( ... )
    {
        destrRange( to, newRing.begin() );
        throw;
    }
    swap( m_ring, newRing );
    m_read     = m_ring.begin();
    m_write    = to;
    m_capacity = newCap;
}

template<typename T, typename Alloc>
void swap( ring_buffer<T, Alloc> &a, ring_buffer<T, Alloc> &b )
{
    swap( a.m_ring,     b.m_ring     );
    swap( a.m_read,     b.m_read     );
    swap( a.m_write,    b.m_write    );
    swap( a.m_capacity, b.m_capacity );
    swap( a.m_size,     b.m_size     );
}

#if defined(_MSC_VER)
    #pragma warning(pop)
#endif
#if defined(__llvm__)
    #pragma clang diagnostic pop
#endif

有很多关于循环缓冲区的虚假信息。 首先,它是一个双端队列。 每当您看到 2 个指针或索引时,您可能正在处理一个双端队列,并且您会经常看到与循环缓冲区相关的头和尾以及读写指针。 但这都是错误的,循环缓冲区是一个双端队列,因此与双向链表相关,它也可以作为双端队列。 所以,你应该考虑的是第一个和最后一个节点,而不是头和尾,就像双向链表一样。 然后你需要决定, first == last是否意味着缓冲区为空。 如果是这样,你可以使用 2 个指针(索引)来实现缓冲区,但如果不是,那么 3。最重要的是查看关于双端队列的文献,因为不同的人倾向于以不同的方式实现他们的循环缓冲区(头部和尾部经常切换角色,例如)和双端队列通常在学术上更明确地处理。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM