Correct way to set the size of a std::vector

16,726

Solution 1

You're doing things in the wrong order.

  1. resize to the max size you want your buffer to accept.
  2. Store the data (which must be smaller than the vector size).
  3. resize to the real data size.

Your problem of "disappearing data" is because when you copy the data the first time, your vector has no size only capacity (ie. pre-reserved memory without actually using it to hold data). When you reserve again, the size is still 0 so the vector is free to optimize out the data copy since it knows it must only keep the first size() elements (ie. 0).

In other words:

  • capacity() = how much data you could put in the vector without triggering reallocation.
  • size() = how much data you're really using (and the vector will keep only that data across reallocations)

What's more, accessing the vector elements past its current size() is Undefined Behaviour (it may appear to work with integral types but think about what would happen with uninitialized objects...). Don't do that.

Solution 2

recv straight into the buffer, something along the lines of:

std::vector< unsigned char > buffer( 1024 );
buffer.resize( recv( &buffer[0], buffer.size() ) );

Depending on if recv can return error codes you might have to check before resizing.

Share:
16,726
Devolus
Author by

Devolus

Assembly, C/C++, SQL and Java developer. Been working in the industry for over 20 years now, and still love programming for a hobby.

Updated on June 14, 2022

Comments

  • Devolus
    Devolus over 1 year

    From what I read, std::vector is the appropriate structure to use when interfacing with c function requiring a contiguous memory byte array. However I was wondering how I can determine the size of the array in some cases

    I have written a small sample program to illustrate what I mean.

    int main(int argc, char *argv[])
    {
        std::vector<unsigned char>v;
        unsigned char p[1024];
    
        sprintf((char*)&p[0], "%10d", 10);
        cout << "Size: " << v.size() << " Length: " << v.capacity() << endl;
        v.reserve(30);
        cout << "Size: " << v.size() << " Length: " << v.capacity() << endl;
        memcpy(&v[0], &p[0], 20);
        cout << "Size: " << v.size() << " Length: " << v.capacity() << endl;
        v.reserve(50);
        cout << "Size: " << v.size() << " Length: " << v.capacity() << endl;
        v.reserve(0);
        cout << "Size: " << v.size() << " Length: " << v.capacity() << endl;
        v.resize(20);
        cout << "Size: " << v.size() << " Length: " << v.capacity() << endl;
        v.resize(0);
        cout << "Size: " << v.size() << " Length: " << v.capacity() << endl;
    
        return 0;
    }
    

    The output is (not much surprising):

    Size: 0 Length: 0
    Size: 0 Length: 30
    Size: 0 Length: 30
    Size: 0 Length: 50
    Size: 0 Length: 50
    Size: 20 Length: 50
    Size: 0 Length: 50
    

    The reason why I did this is, because I reserve a buffer of a certain size and then pass this memory to a socket via recv(). Since I have to pass the memory as a pointer, there is no way that the vector size gets adjusted according to what recv returns. Now when the received number of bytes is smaller then the buffer, I would have thought that I can somehow adjust the size of the vector, so when I pass it back, the caller can do v.size() and the the number of elements aka returned by receive.

    When I looked at the data from the above example, when using resize() the size of the buffer is adjusted correctly, but the data is gone. So do I really have to copy the memory individually into a new vector just to get the correct size? This sounds like a really unnecessary overhead to me. Or is there some way to tell the vector how many elements it currently is supposed to hold?

  • James Kanze
    James Kanze over 10 years
    If you don't set the size before, you'll never see what recv got. (Also, of course, you have undefined behavior.)
  • Devolus
    Devolus over 10 years
    And this will guaruantee that the data is not lost during the resize? Because this is what I simulated with the memcpy in the short sample. When I call receive, the OS will place the data from the socket into the buffer and I'm aware that the vector can not how much this is. That's why I need to adjust size() afterwards, so the vector knows how much elements it holds, but it obviously shouldn't loose the data in the process, which apparently it does, because the vector implementation only cares about the known elements.
  • Matteo Italia
    Matteo Italia over 10 years
    @Devolus: the vector is initialized to hold 1024 elements, so it already knows that there are 1024 valid elements (on which recv writes); resize will just correct the element count to the actually used elements and (perhaps) trim the memory used.
  • Devolus
    Devolus over 10 years
    Thanks, that was indeed the correct answer and I verified it with my testprogram in the debugger. Now I also understand why. :) This also fits my implementation model, as I don't use the constructor in the beginning but want to set the size manually.
  • James Kanze
    James Kanze over 10 years
    @MatteoItalia resize cannot reallocate unless it needs to, so it cannot make the buffer smaller. In C++11, there is a function std::vector<>::shrink_to_fit which can be used to reduce the memory used, or you can do something like std::vector< unsigned char >( v.begin(), v.end() ).swap( v );.