Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Resizing a C++ std::vector<char> without initializing data [duplicate]

With vectors, one can assume that elements are stored contiguously in memory, allowing the range [&vec[0], &vec[vec.capacity()) to be used as a normal array. E.g.,

vector<char> buf; buf.reserve(N); int M = read(fd, &buf[0], N); 

But now the vector doesn't know that it contains M bytes of data, added externally by read(). I know that vector::resize() sets the size, but it also clears the data, so it can't be used to update the size after the read() call.

Is there a trivial way to read data directly into vectors and update the size after? Yes, I know of the obvious workarounds like using a small array as a temporary read buffer, and using vector::insert() to append that to the end of the vector:

char tmp[N]; int M = read(fd, tmp, N); buf.insert(buf.end(), tmp, tmp + M) 

This works (and it's what I'm doing today), but it just bothers me that there is an extra copy operation there that would not be required if I could put the data directly into the vector.

So, is there a simple way to modify the vector size when data has been added externally?

like image 535
user984228 Avatar asked Oct 07 '11 15:10

user984228


People also ask

How do I resize the size of a vector in C++?

C++ Vector Library - resize() Function The C++ function std::vector::resize() changes the size of vector. If n is smaller than current size then extra elements are destroyed. If n is greater than current container size then new elements are inserted at the end of vector.

Does resizing a vector delete data?

Resizing a vector doesn't destroy the values stored in the vector (except for those beyond the new size when shrinking, of course), however growing a vector beyond its capacity will copy (or, in C++11, move) them to a new place, thus invalidating and iterators, pointers or references to those elements.

Can vector have duplicates in C++?

The idea is to insert all vector elements in a set and copy the set's contents back again into the vector. This works as inserting elements into the set removes all duplicates as all set elements must be distinct. Please note that this might change the original ordering of elements in the vector.

What is the correct way to initialize vector in C++?

Begin Declare v of vector type. Call push_back() function to insert values into vector v. Print “Vector elements:”. for (int a : v) print all the elements of variable a.


2 Answers

vector<char> buf; buf.reserve(N); int M = read(fd, &buf[0], N); 

This code fragment invokes undefined behavior. You can't write beyond than size() elements, even if you have reserved the space.

The correct code is like:

vector<char> buf; buf.resize(N); int M = read(fd, &buf[0], N); buf.resize(M); 


PS. Your statement "With vectors, one can assume that elements are stored contiguously in memory, allowing the range [&vec[0], &vec[vec.capacity()) to be used as a normal array" isn't true. The allowable range is [&vec[0], &vec[vec.size()).
like image 172
Robᵩ Avatar answered Sep 22 '22 21:09

Robᵩ


It looks like you can do what you want in C++11 (though I haven't tried this myself). You'll have to define a custom allocator for the vector, then use emplace_back().

First, define

struct do_not_initialize_tag {}; 

Then define your allocator with this member function:

class my_allocator {     void construct(char* c, do_not_initialize_tag) const {         // do nothing     }      // details omitted     // ... } 

Now you can add elements to your array without initializing them:

std::vector<char, my_allocator> buf; buf.reserve(N); for (int i = 0; i != N; ++i)     buf.emplace_back(do_not_initialize_tag()); int M = read(fd, buf.data(), N); buf.resize(M); 

The efficiency of this depends on the compiler's optimizer. For instance, the loop may increment the size member variable N times.

like image 30
Derek Ledbetter Avatar answered Sep 21 '22 21:09

Derek Ledbetter