Trying to adapt a circular buffer/ring buffer using String

Hello !

As the title says I am trying to adapt a circular buffer I've found online.

#include <iostream>
#include <string>
#include <vector>

struct ring_buffer
{
    ring_buffer( std::size_t cap ) : buffer(cap) {}
    bool empty() const { return sz == 0 ; }
    bool full() const { return sz == buffer.size() ; }

    void push( std::string str )
    {
        if( last >= buffer.size() ) last = 0 ;
        buffer[last] = str ;
        ++last ;
        if( full() ) first = (first+1) %  buffer.size() ;
        else ++sz ;
    }

    std::string& operator[] ( std::size_t pos )
    {
        auto p = ( first + pos ) % buffer.size() ;
        return buffer[p] ;
    }

    std::ostream& print( std::ostream& stm = std::cout ) const
    {
        if( first < last )
            for( std::size_t i = first ; i < last ; ++i ) std::cout << buffer[i] << ' ' ;
        else
        {
            for( std::size_t i = first ; i < buffer.size() ; ++i ) std::cout << buffer[i] << ' ' ;
            for( std::size_t i = 0 ; i < last ; ++i ) std::cout << buffer[i] << ' ' ;
        }
        return stm ;
    }

    private:
        std::vector<std::string> buffer ;
        std::size_t first = 0 ;
        std::size_t last = 0 ;
        std::size_t sz = 0 ;
};

int main()
{
    ring_buffer rb(8) ;

    for( int i = 10 ; i < 30 ; ++i )
    {
        rb.push( std::to_string(i) ) ;
        rb.print() << '\n' ;
    }
}

This is what I found. It seems simple enough, right ? Well, I managed to mess it up:

struct ring_buffer
{
    ring_buffer(size_t cap) : buffer(cap) {}

    bool empty() const { return sz == 0 ; }
    bool full() const { return sz == buffer.size() ; }

    void push( String str )
    {
        if(last >= buffer.size()) last = 0 ;
        buffer[last] = str ;
        ++last ;
        if(full()) 
			first = (first+1) %  buffer.size() ;
        else ++sz ;
    }

    // String operator[] ( size_t pos )
    // {
    //     auto p = ( first + pos ) % buffer.size() ;
    //     return buffer[p] ;
    // }

    String print() const
    {
        if( first < last )
            for( size_t i = first ; i < last ; ++i ) return (String)buffer[i] + "
";
        else
        {
            for( size_t i = first ; i < buffer.size() ; ++i ) return (String)buffer[i] + "
";
            for( size_t i = 0 ; i < last ; ++i ) return (String)buffer[i] + "
";
        }
		return String();
    }

    private:
        std::vector<String> buffer ;
        size_t first = 0 ;
        size_t last = 0 ;
        size_t sz = 0 ;
};

As you can imagine, I ended up messing with the print() function. Now it only prints one element from the buffer, instead of them all.
I also don't understand why are there 2 for structures inside the else.

Do you have any clue ? Because I most certainly don't.

Thank you !

I also don't understand why are there 2 for structures inside the else.

There really is no such thing as a circular array in C or C++. There is a linear array. You can pretend that the end is the beginning. To do that, you would print from some position to the end, and then from the beginning to another position. That requires two for loops.

The original code did not return values. Your new code does. Nothing after a return statement is executed, so the behavior you are seeing is what I would expect.

It is not a good idea to use the String (capital S) class on an Arduino as it can cause memory corruption in the small memory on an Arduino. This can happen after the program has been running perfectly for some time. Just use cstrings - char arrays terminated with '\0' (NULL).

If their general use is risky my guess is trying to use Strings in a circular buffer will definitely fail.

...R