Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Optimal way to fill std::vector<char> buffer

Tags:

c++

stdvector

This buffer should contain slots (three in this example) of equal length ( 20 in this example)
The buffer has to have contiguous memory so that it can be passed to a C function in non-const fashion.

const int slot_size = 20;
std::vector<char> vbuffer;

This function takes a string, copies to a temporary buffer of the required size then appeds it to vbuffer

void prepBuffer( const std::string& s)
{
  std::vector<char> temp(slot_size);
  std::copy(s.c_str(), s.c_str() + s.length() + 1, temp.begin());
  vbuffer.insert(vbuffer.end(), temp.begin(), temp.end());
}

Testing the function

int main()
{
  vbuffer.reserve(60);
  prepBuffer( "Argentina");
  prepBuffer( "Herzegovina");
  prepBuffer( "Zambia");

  cout << &vbuffer[0] << endl;
  cout << &vbuffer[20] << endl;
  cout << &vbuffer[40] << endl;
}

Question. There is a lot of string copying in my prepBuffer function. I am looking for a better way to fill up vbuffer with minimal copying
EDIT
The size of slots is determined elsewhere in the program. But it is not known at compile time.

EDIT

In line with my accepted answer below, I have settled on this version

void prepBuffer(const std::string& s)
{
  assert(s.size() < slot_size );
  vbuffer.insert(vbuffer.end(), s.begin(), s.end());
  vbuffer.insert(vbuffer.end(), slot_size - s.size(), '\0' ); 
}


Suggestions are still welcome

like image 852
user841550 Avatar asked Jan 18 '23 15:01

user841550


2 Answers

How about this:

vbuffer.reserve(vbuffer.size() + 20);
vbuffer.insert(vbuffer.end(), s.begin(), s.end());
vbuffer.insert(vbuffer.end(), 20 - s.size(), '\0');

An additional check on the string length is recommended, along with a policy for handling over-long strings (e.g. assert(s.size() < 20);).

like image 103
Kerrek SB Avatar answered Jan 21 '23 05:01

Kerrek SB


If you don't use std::string at all and avoid the temporary std::vector, you can easily do this without any extra dynamic allocation.

template <unsigned N>
void prepBuffer(char const (&s)[N])
{
    std::copy(s, s + N, std::back_inserter(vbuffer));
    vbuffer.resize(vbuffer.size() - N + 20);
}

Or, since the number of characters to be written is known ahead of time, you could just as easily use a nontemplate function:

void prepBuffer(char const* s)
{
    unsigned n = vbuffer.size();
    vbuffer.resize(n + 20);
    while (*s && n != vbuffer.size())
    {
        vbuffer[n] = *s;
        ++n;
        ++s;
    }

    assert(*s == 0 && n != vbuffer.size());
    // Alternatively, throw an exception or handle the error some other way
}
like image 34
James McNellis Avatar answered Jan 21 '23 05:01

James McNellis