75

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);
2
  • There is a 'problem' with this: int pv[4] = { 4, 4, 4, 4}; vector<int> v (pv); it actually copies the contents of pv into v ... you just have to be aware of that Commented Oct 8, 2010 at 8:32
  • You can't have a vector<int> share memory with an array, but you could have a vector<int, some_allocator> share memory. Commented Mar 21, 2024 at 13:33

5 Answers 5

98

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.

Sign up to request clarification or add additional context in comments.

8 Comments

"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: Good point. Just be sure you reserve() before you get the pointer! :)
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(&pv[0], &pv[4]);, using the example you added to your question.
I 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.
@JosephGarvin: The array_ref<T> and string_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 an enhanced_cstring<T> class template in the Boost-licensed CxxReflect library that has been most useful).
|
41

In C++11, you can use vector::data() to get C array pointer.

Comments

21
int* pv = &(v[0]);

Note that this is only the case for std::vector<>, you cannot do the same with other standard containers (except for std::string).

Scott Meyers covers this topic extensively in his books.

4 Comments

"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.
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.
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...
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"...
18

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.

Comments

0

One way of protecting yourself against size changes is to reserve the maximal space (or larger) that you will need:

std::vector<int> v(4,100); //Maybe need 
v.reserve(40);             //reallocate to block out space for 40 elements

This will ensure that push_backs won't cause reallocation of the existing data.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.