Is it more efficient to copy a vector by reserving and copying, or by creating and swapping?

403,784

Solution 1

Your second example does not work if you send the argument by reference. Did you mean

void copyVecFast(vec<int> original) // no reference
{

  vector<int> new_;
  new_.swap(original); 
}

That would work, but an easier way is

vector<int> new_(original);

Solution 2

They aren't the same though, are they? One is a copy, the other is a swap. Hence the function names.

My favourite is:

a = b;

Where a and b are vectors.

Solution 3

This is another valid way to make a copy of a vector, just use its constructor:

std::vector<int> newvector(oldvector);

This is even simpler than using std::copy to walk the entire vector from start to finish to std::back_insert them into the new vector.

That being said, your .swap() one is not a copy, instead it swaps the two vectors. You would modify the original to not contain anything anymore! Which is not a copy.

Solution 4

Direct answer:

  • Use a = operator

We can use the public member function std::vector::operator= of the container std::vector for assigning values from a vector to another.

  • Use a constructor function

Besides, a constructor function also makes sense. A constructor function with another vector as parameter(e.g. x) constructs a container with a copy of each of the elements in x , in the same order.

Caution:

  • Do not use std::vector::swap

std::vector::swap is not copying a vector to another, it is actually swapping elements of two vectors, just as its name suggests. In other words, the source vector to copy from is modified after std::vector::swap is called, which is probably not what you are expected.

  • Deep or shallow copy?

If the elements in the source vector are pointers to other data, then a deep copy is wanted sometimes.

According to wikipedia:

A deep copy, meaning that fields are dereferenced: rather than references to objects being copied, new copy objects are created for any referenced objects, and references to these placed in B.

Actually, there is no currently a built-in way in C++ to do a deep copy. All of the ways mentioned above are shallow. If a deep copy is necessary, you can traverse a vector and make copy of the references manually. Alternatively, an iterator can be considered for traversing. Discussion on iterator is beyond this question.

References

The page of std::vector on cplusplus.com

Solution 5

new_vector.assign(old_vector.begin(),old_vector.end()); // Method 1
new_vector = old_vector; // Method 2
Share:
403,784

Related videos on Youtube

Cody Gray
Author by

Cody Gray

Molecular biologist and historian by formal training, but software developer by passion. Also now by career. Need a smart, motivated, and hard-working desktop or embedded developer? Hire me! Send mail to my first name at codygray.com. My deepest areas of expertise are the x86 microarchitecture and the Windows API, but my interests span multiple platforms and diverse disciplines. At work, I design, build, and maintain speciality embedded hardware and software to perform data-acquisition and real-time signal processing from sensors, primarily targeting the aerospace industry. These days, I mostly write code in C++ or assembly. I also know C, C#, VB.NET, VB 6, and a variety of shell-scripting languages. Passionate about developing robust, efficient systems. I enjoy the challenge of solving problems and learn new things quickly. I've an excellent eye for quality and detail. I'm here because I find great reward in teaching others and because I want to make the Internet a better place. Brevity is not my strong suit. Kind, not nice. I have strong ideas and make a habit of openly challenging assumptions. People don't like having their assumptions challenged, so this sometimes leads to confrontation. Nothing I say is meant to offend; please don't take it personally. Progress cannot happen without confrontation, so think for yourself and question everything. If you have a technical question you think I might be able to answer, please ask it on the site so that everyone may contribute and benefit. If you disagree with one of the actions I've taken as a moderator, please bring it up for discussion on Meta Stack Overflow (do not send me a personal email about on-site moderation actions; those get ignored, if you're lucky).

Updated on August 01, 2020

Comments

  • Cody Gray
    Cody Gray almost 4 years

    I am trying to efficiently make a copy of a vector. I see two possible approaches:

    std::vector<int> copyVecFast1(const std::vector<int>& original)
    {
      std::vector<int> newVec;
      newVec.reserve(original.size());
      std::copy(original.begin(), original.end(), std::back_inserter(newVec));
      return newVec;
    }
    
    std::vector<int> copyVecFast2(std::vector<int>& original)
    {
      std::vector<int> newVec;
      newVec.swap(original);
      return newVec;
    }
    

    Which of these is preferred, and why? I am looking for the most efficient solution that will avoid unnecessary copying.

  • David Rodríguez - dribeas
    David Rodríguez - dribeas about 15 years
    In fact the approach is passing by value, the compiler calls the copy constructor, and then swapping that newly created element. That is why rlbond suggests calling the copy constructor directly to achieve the same effect.
  • Eyad Ebrahim
    Eyad Ebrahim about 11 years
    However, you can't call rlbon without a function that passes the original as val. Otherwise, the original one will be empties. The second solution made sure that you will always call by value and hence you will not lose the date in the original vector. (Assuming swap deals with pointers)
  • Jonathan.
    Jonathan. over 9 years
    Won't that move the elements of b to a (leaving b with size == 0)?
  • Daniel Earwicker
    Daniel Earwicker over 9 years
    @Jonathan. Assuming you're talking about a = b then no. Assignment means: make a equal b without changing b. By contrast, std::swap(a, b) would exchange their contents (so b's size would now be whatever a's had been before). You are perhaps thinking of a move operation (as occurs in C++11, but not in an ordinary assignment like this). Such a move would leave b in an, ahem, "interesting" state - see stackoverflow.com/questions/17730689/…
  • Daniel Earwicker
    Daniel Earwicker over 9 years
    Note that there is an old C++ standard library class called auto_ptr which implemented assignment wrongly so that it performed a move.
  • Jonathan.
    Jonathan. over 9 years
    @Daniel, this page says that in C++11 if the vector isn't const then the = operator is a move?
  • Daniel Earwicker
    Daniel Earwicker over 9 years
    @Jonathan. Which page says that?
  • Jonathan.
    Jonathan. over 9 years
    @Daniel, sorry this page (cplusplus.com/reference/vector/vector/operator=) when you click on the C++ tabs
  • Daniel Earwicker
    Daniel Earwicker over 9 years
    @Jonathan. Note the double ampersand &&. That version will only be used for an rvalue reference. It won't match any non-const value (such as b in my example above). You can turn b into one by saying a = std::move(b); See en.cppreference.com/w/cpp/language/value_category for even greater levels of complexity.
  • ABcDexter
    ABcDexter over 9 years
    Good, it works. But it's not working for an array of vectors: for e.g: vector<int> A[n];
  • sdd
    sdd over 6 years
    That is swap, not copy.
  • rlbond
    rlbond over 6 years
    @sdd - no it's not. Check the argument list. original is a copy of the function argument.
  • truthadjustr
    truthadjustr almost 4 years
    More flexible for me is a = b; because I already have member field a and I just need to assign it with the new value from b
  • truthadjustr
    truthadjustr almost 4 years
    This is also my favorite. I traced into it, and it created exact copy of member fields unsigned char pubkey[32]; in my object. But of course, &pubkey have different addresses. But the byte array contents are equal. If your object has member fields like unsigned char* pbuf; then the address value of pbuf would match in the two objects. Meaning, that doing pbuf[0] = 0x42; inside object1 , produces the same change in object2 for this member field.
  • Shubham Sharma
    Shubham Sharma almost 4 years
    @rlbond Accidentally downvoted the answer :(, Can you please edit the post, so that i can remove the downvote and give the upvote?