How do you copy the contents of an array to a std::vector in C++ without looping?

216,363

Solution 1

If you can construct the vector after you've gotten the array and array size, you can just say:

std::vector<ValueType> vec(a, a + n);

...assuming a is your array and n is the number of elements it contains. Otherwise, std::copy() w/resize() will do the trick.

I'd stay away from memcpy() unless you can be sure that the values are plain-old data (POD) types.

Also, worth noting that none of these really avoids the for loop--it's just a question of whether you have to see it in your code or not. O(n) runtime performance is unavoidable for copying the values.

Finally, note that C-style arrays are perfectly valid containers for most STL algorithms--the raw pointer is equivalent to begin(), and (ptr + n) is equivalent to end().

Solution 2

There have been many answers here and just about all of them will get the job done.

However there is some misleading advice!

Here are the options:

vector<int> dataVec;

int dataArray[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
unsigned dataArraySize = sizeof(dataArray) / sizeof(int);

// Method 1: Copy the array to the vector using back_inserter.
{
    copy(&dataArray[0], &dataArray[dataArraySize], back_inserter(dataVec));
}

// Method 2: Same as 1 but pre-extend the vector by the size of the array using reserve
{
    dataVec.reserve(dataVec.size() + dataArraySize);
    copy(&dataArray[0], &dataArray[dataArraySize], back_inserter(dataVec));
}

// Method 3: Memcpy
{
    dataVec.resize(dataVec.size() + dataArraySize);
    memcpy(&dataVec[dataVec.size() - dataArraySize], &dataArray[0], dataArraySize * sizeof(int));
}

// Method 4: vector::insert
{
    dataVec.insert(dataVec.end(), &dataArray[0], &dataArray[dataArraySize]);
}

// Method 5: vector + vector
{
    vector<int> dataVec2(&dataArray[0], &dataArray[dataArraySize]);
    dataVec.insert(dataVec.end(), dataVec2.begin(), dataVec2.end());
}

To cut a long story short Method 4, using vector::insert, is the best for bsruth's scenario.

Here are some gory details:

Method 1 is probably the easiest to understand. Just copy each element from the array and push it into the back of the vector. Alas, it's slow. Because there's a loop (implied with the copy function), each element must be treated individually; no performance improvements can be made based on the fact that we know the array and vectors are contiguous blocks.

Method 2 is a suggested performance improvement to Method 1; just pre-reserve the size of the array before adding it. For large arrays this might help. However the best advice here is never to use reserve unless profiling suggests you may be able to get an improvement (or you need to ensure your iterators are not going to be invalidated). Bjarne agrees. Incidentally, I found that this method performed the slowest most of the time though I'm struggling to comprehensively explain why it was regularly significantly slower than method 1...

Method 3 is the old school solution - throw some C at the problem! Works fine and fast for POD types. In this case resize is required to be called since memcpy works outside the bounds of vector and there is no way to tell a vector that its size has changed. Apart from being an ugly solution (byte copying!) remember that this can only be used for POD types. I would never use this solution.

Method 4 is the best way to go. It's meaning is clear, it's (usually) the fastest and it works for any objects. There is no downside to using this method for this application.

Method 5 is a tweak on Method 4 - copy the array into a vector and then append it. Good option - generally fast-ish and clear.

Finally, you are aware that you can use vectors in place of arrays, right? Even when a function expects c-style arrays you can use vectors:

vector<char> v(50); // Ensure there's enough space
strcpy(&v[0], "prefer vectors to c arrays");

Hope that helps someone out there!

Solution 3

If all you are doing is replacing the existing data, then you can do this

std::vector<int> data; // evil global :)

void CopyData(int *newData, size_t count)
{
   data.assign(newData, newData + count);
}

Solution 4

Since I can only edit my own answer, I'm going to make a composite answer from the other answers to my question. Thanks to all of you who answered.

Using std::copy, this still iterates in the background, but you don't have to type out the code.

int foo(int* data, int size)
{
   static std::vector<int> my_data; //normally a class variable
   std::copy(data, data + size, std::back_inserter(my_data));
   return 0;
}

Using regular memcpy. This is probably best used for basic data types (i.e. int) but not for more complex arrays of structs or classes.

vector<int> x(size);
memcpy(&x[0], source, size*sizeof(int));

Solution 5

std::copy is what you're looking for.

Share:
216,363
bsruth
Author by

bsruth

Updated on July 08, 2022

Comments

  • bsruth
    bsruth almost 2 years

    I have an array of values that is passed to my function from a different part of the program that I need to store for later processing. Since I don't know how many times my function will be called before it is time to process the data, I need a dynamic storage structure, so I chose a std::vector. I don't want to have to do the standard loop to push_back all the values individually, it would be nice if I could just copy it all using something similar to memcpy.

  • mmocny
    mmocny over 15 years
    I was going to recommend this approach.
  • Pavel Kucherbaev
    Pavel Kucherbaev over 15 years
    It is most likely more efficient to resize your vector up front if you know the size ahead of time, and not use the back_inserter.
  • David Nehme
    David Nehme over 15 years
    you could add my_data.reserve(size)
  • mmocny
    mmocny over 15 years
    Note that internally this is doing exactly what you seem to want to avoid. It is not copying bits, it is just looping and calling push_back(). I guess you only wanted to avoid typing the code?
  • Martin York
    Martin York over 15 years
    Wjy not use the vector constructor to copy the data?
  • John Dibling
    John Dibling over 15 years
    If you are using a back_inserter, you don't need to pre-reserve the size of the vector you're copying to. back_inserter does a push_back().
  • ReaperUnreal
    ReaperUnreal over 15 years
    Doesn't that depend on the implementation of std::vector?
  • Ruud Schroën
    Ruud Schroën over 15 years
    That's horrible! You are filling the array twice, one with '0's, then with the proper values. Just do: std::vector<int> myArray(source, source + item_count); and trust your compiler to produce the memcpy!
  • bradtgmurray
    bradtgmurray over 15 years
    The reason why looping and calling push_back is bad is because you might force the vector to resize multiple times if the array is long enough.
  • bsruth
    bsruth over 15 years
    because that would only work for the first iteration. When adding more data on subsequent iterations, I can't just use the constructor.
  • Drew Hall
    Drew Hall over 15 years
    @bradtgmurray: I think any reasonable implementation of the "two iterators" vector constructor I suggested above would call std::distance() first on the two iterators to get the needed number of elements, then allocate just once.
  • Drew Hall
    Drew Hall over 15 years
    @bradtgmurray: Even push_back() wouldn't be too bad because of the exponential growth of vectors (aka "amortized constant time"). I think runtime would only be on the order of 2x worse in the worst case.
  • MSalters
    MSalters over 15 years
    @ Method1, std::copy may use traits to optimize the copy (implementations exist). In particular, vector-to-vector copies without back_inserters are likely to be faster than memcpy(). std::memcpy() must deal with unaligned memory. std::copy<int*>() does not.
  • MP24
    MP24 over 15 years
    And if the vector is already there, a vec.clear(); vec.insert(vec.begin(), a, a + n); would work as well. Then you wouldn't even require a to be a pointer, just an iterator, and the vector assignment would be failry general (and the C++/STL way).
  • Drew Hall
    Drew Hall over 15 years
    You can't safely & portably refer to "&dataArray[dataArraySize]"--it's dereferencing a past-the-end pointer/iterator. Instead, you can say dataArray + dataArraySize to get the pointer without having to dereference it first.
  • Roland Illig
    Roland Illig about 13 years
    @Drew: yes, you can, at least in C. It is defined that &expr doesn't evaluate expr, it only computes the address of it. And a pointer one past the last element is perfectly valid, too.
  • Saurabh
    Saurabh almost 11 years
    Maybe this should be a comment on one of the other answers, as you do not actually propose a solution.
  • mMontu
    mMontu over 10 years
    Another alternative when unable to construct would be assign: vec.assign(a, a+n), which would be more compact than copy & resize.
  • Jorge Leitao
    Jorge Leitao over 10 years
    Have you tried doing method 4 with 2? i.e. reserving the space before inserting. It seems that if the data size is big, multiple insertions will need multiple reallocations. Because we know the size a priori, we can do the reallocation, before inserting.
  • Don Scott
    Don Scott over 9 years
    Simple to understand and definitely the fastest solution (it's just a memcpy behind the scenes).
  • Toby Speight
    Toby Speight over 7 years
    Whilst this code snippet is welcome, and may provide some help, it would be greatly improved if it included an explanation of how and why this solves the problem. Remember that you are answering the question for readers in the future, not just the person asking now! Please edit your answer to add explanation, and give an indication of what limitations and assumptions apply.
  • Jim
    Jim over 6 years
    Is deta.assign faster than data.insert?
  • jyavenard
    jyavenard about 6 years
    all those proposals but method 5 have undefined behaviour if the original array is empty
  • mavavilj
    mavavilj almost 6 years
    Wait, what's myints?
  • Chef Pharaoh
    Chef Pharaoh over 4 years
    This is great (std::copy) because it gives more flexibility, especially if you don't want to copy the entire vector and can append another vector.
  • Ruslan
    Ruslan over 4 years
    @jyavenard ISO C++ forbids zero-size array ‘dataArray’ [-Wpedantic]
  • Ruslan
    Ruslan over 4 years
    @MattyT what is the point of method 5? Why make an intermediate copy of the data?
  • Aconcagua
    Aconcagua over 4 years
    I personally would rather profit from arrays decaying to pointers automatically: dataVec.insert(dataVec.end(), dataArray, dataArray + dataArraySize); – appears much clearer to me. Cannot gain anything from method 5 either, only looks pretty inefficient – unless compiler is able to optimise the vector away again.
  • Mikhail Vasilyev
    Mikhail Vasilyev almost 3 years
    For primitive data types, method 4 is still less efficient than using std::unique_ptr + memcpy because it boils down to memmove preceded by a few if-branches.
  • willSapgreen
    willSapgreen over 2 years
    I guess this example is from cplusplus.com/reference/algorithm/copy, where you can find myints :)