views:

751

answers:

3

I would like to be able to convert between std::vector and its underlying C array int* without explicitly copying the data.

Does std::vector provide access to the underlying C array? I am looking for something like this

vector<int> v (4,100)
int* pv = v.c_array();

EDIT:

Also, is it possible to do the converse, i.e. how would I initialize an std::vector from a C array without copying?

int pv[4] = { 4, 4, 4, 4};
vector<int> v (pv);
+13  A: 
int* pv = &v[0]

Note that this is only the case for std::vector<>, you can not do the same with other standard containers.

Scott Meyers covers this topic extensively in his books.

Dan
I believe this is even guaranteed to work by the standard.
Omnifarious
"you can not do the same with other standard containers" - IIRC you will be able to do it with string in C++0x, and in practice pretty much every implementation does actually guarantee that string's storage is contiguous.
Steve Jessop
You can get a read-only array containing the elements of a `std::string` using its `c_str()` or `data()` members. Because of this, while the standard doesn't require strings to be stored contiguously in memory, it would be very odd and inefficient not to do so.
James McNellis
I assume the standard envisaged strings might be implemented as a rope-like thing, so that appending and sub-stringing are faster. Access would be slightly slower (like `deque` vs `vector`), and `c_str()` would incur a hefty penalty the first time it's called. As it turned out, implementers all seem to have weighed up the trade-off and wanted nothing to do with it...
Steve Jessop
I've always thought it would be interesting to have a C/C++ implementation that made "bizarre" assumptions--like debugging iterators (not just a simple pointer), but (much) more so. While still be standards-compliant, of course.
Dan
I think so too. It would be really useful when you're writing portable code, to compile and test it with a variety of different common and not-so-common implementation details, beyond what pedantic compilers warn about. But look what happened when C compilers started actually using strict aliasing rules - half the code breaks, and everyone gets very confused except for the kind of smug standards-lawyer who hangs out on SO ;-) Too few programmers are actually pedantic enough to be able to use such a thing - you still get people advising that more than -O2 on gcc is "dangerous"...
Steve Jessop
+9  A: 

If you have very controlled conditions, you can just do:

std::vector<int> v(4,100);
int* pv = &v[0];

Be warned that this will only work as long as the vector doesn't have to grow, and the vector will still manage the lifetime of the underlying array (that is to say, don't delete pv). This is not an uncommon thing to do when calling underlying C APIs, but it's usually done with an unnamed temporary rather than by creating an explicit int* variable.

Drew Hall
+28  A: 

You can get a pointer to the first element as follows:

int* pv = &v[0];

This pointer is only valid as long as the vector is not reallocated. Reallocation happens automatically if you insert more elements than will fit in the vector's remaining capacity (that is, if v.size() + NumberOfNewElements > v.capacity(). You can use v.reserve(NewCapacity) to ensure the vector has a capacity of at least NewCapacity.

Also remember that when the vector gets destroyed, the underlying array gets deleted as well.

James McNellis
"so long as you do not add additional elements to the vector" - without reserving space first. If you `reserve()`, then you can add elements up to the capacity you reserved, and guarantee that references and iterators are still valid.
Steve Jessop
@Steve: Good point. Just be sure you reserve() before you get the pointer! :)
Drew Hall
@Steve: That's true, though I think I'd find it a tad disconcerting if I saw code inserting elements into a vector _and_ using pointers to elements in the vector that were obtained before the insertion. Still, I've modified that paragraph to try and more clearly state when reallocation happens.
James McNellis
Thanks for your answer. What about the reverse conversion? How can I initialize an `std::vector<int>` from a C array `int*` without copying?
celil
The reverse isn't possible; the STL containers manage their own memory. You can't create a vector and have it manage some array that you allocated elsewhere. The easiest way to _copy_ an array into a vector would be to use `std::vector<int> v(`, using the example you added to your question.
James McNellis