Converting between C++ std::vector and C array without copying
Solution 1
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.
Solution 2
In c++11, you can use vector::data() to get C array pointer.
Solution 3
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.
Solution 4
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.
D R
Updated on July 06, 2022Comments
-
D R almost 2 years
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);
-
Steve Jessop over 14 years"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 over 14 years"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.
-
James McNellis over 14 yearsYou can get a read-only array containing the elements of a
std::string
using itsc_str()
ordata()
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. -
Drew Hall over 14 years@Steve: Good point. Just be sure you reserve() before you get the pointer! :)
-
James McNellis over 14 years@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.
-
Steve Jessop over 14 yearsI 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
vsvector
), andc_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... -
D R over 14 yearsThanks for your answer. What about the reverse conversion? How can I initialize an
std::vector<int>
from a C arrayint*
without copying? -
James McNellis over 14 yearsThe 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(&pv[0], &pv[4]);
, using the example you added to your question. -
Steve Jessop over 14 yearsI 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"...
-
Joseph Garvin almost 12 yearsI think it's actually too bad that vector doesn't have a consuming constructor that would let it take ownership of an existing array provided the length. Makes interop with C libraries harder.
-
James McNellis almost 12 years@JosephGarvin: The
array_ref<T>
andstring_ref<T>
class templates are very helpful for this purpose (neither is standard--yet, and I don't know of any open source implementations with those exact interfaces, but I have anenhanced_cstring<T>
class template in the Boost-licensed CxxReflect library that has been most useful). -
Bulletmagnet over 8 yearsI prefer to use
&v.front()
(which is the same as&*v.begin()
but looks less redundant). This saves having to add 0 tobegin()
before dereferencing. The compiler may or may not be able to optimize away the addition.