Copying std::vector: prefer assignment or std::copy?
Generally I would strongly prefer v2 = v1
:
- It is shorter and makes the intent more clear
std::copy
won't work ifv2
doesn't have the same length asv1
(it won't resize it, so it will retain some of the old elements best case (v2.size() > v1.size()
and overwrite some random data used elsewhere in the program worst case- If
v1
is about to expire (and you use C++11) you can easily modify it tomove
the contents - Performancewise assignment is unlikely to be slower then
std::copy
, since the implementers would probably usestd::copy
internally, if it gave a performance benefit.
In conclusion, std::copy
is less expressive, might do the wrong thing and isn't even faster. So there isn't really any reason to use it here.
Allocation free std::vector copy when using assignment operator
Standard doesn't guarantee that there would be no allocations. According to the C++11 Standard the effect of b = a;
is as if b.assign(a.begin(), a.end())
(with surplus b's elements destroyed, if any) which result is "Replaces elements in b with a copy of [a.begin(), a.end())". Nothing about allocations but with the C++20 Standard (maybe earlier) we have an additional statement: "Invalidates all references, pointers and iterators referring to the elements of b". Which means allocation is possible and the capacity()
isn't mentioned anywhere in these guarantees to prevent it in your particular case.
On the other hand, in practice, why would it reallocate the memory if there is enough already?
Assignment and std::copy of a vector
If you are writing your own copy constructor you should use member initialization and directly construct the vector from the source.
A::A(const A& a) : vs(a.vs) {}
Now if all of your class members are copy constructable then you do not need to have a copy constructor as the one provided by the compiler will be sufficient.
Is it more efficient to copy a vector by reserving and copying, or by creating and swapping?
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);
std::vector capacity after copying
All you're guaranteed is that:
- The vector has enough capacity to store its elements. (Obviously.)
- The vector won't get a new capacity until it's current capacity is full.*
So how much extra or little an implementation wants to put is up to the implementation. I think most will make capacity match size, when copying, but it cannot lower capacity. (Because of number 2 above; reallocating while there's enough room is not allowed.)
* Mostly. See Charles' comments below.
Copy constructor vs assignment operator with STL vector
Is there any way a
vector
can be declared and instantiated while skipping the copying operation?
No. When you do vector<A> obj {1,2,3}
the compiler creates a std::initializer_list<A>
from the values provided. That std::initializer_list
creation is the reason you see the three normal constructor calls. The vector then has to copy those elements because the underlying storage for those elements is const
. There is no was to get around that with list initialization. Even vector<A> obj {A(1),A(2),A(3)}
would still cause copies.
If you don't want that then one thing you can do is create storage for the elements using reserve
, and then use emplace_back
to directly construct the objects in the vector like
vector<A> obj;
obj.reserve(3);
for (int i = 1; i < 4, ++i)
obj.emplace_back(i);
Doing
obj_1 = obj
, if myobj_1
was previously initialized results in calling the copy constructor instead ofoperator=
function inside my class A as I was expecting?
This is because obj_1
is empty. Since it is empty, there is no element to call the assignment operator on. Instead what it does is create elements in obj_1
that are copies of obj
and the most efficient way to do that is to just call the copy constructor instead of default constructing the objects and then assigning to them.
If you had
vector<A> obj {1,2,3};
vector<A> obj_1 {3, 4, 5};
obj_1 = obj;
Instead then you would see the assignment operator be used instead since there are objects to actually assign to.
Copying vectors without using the element copy assignment operator - portability
The standard requires that for y.assign(it1, it2)
to work, the element type T
be CopyAssignable. That is, copy constructible and assignable. Your type is not assignable, so you can't rely on assign
. The same goes for y = x
. Section 23.2.3 of the standard describes the requirements for various sequence container operations.
If you have an existing vector y
, you can construct a new vector z
then swap it with y
:
{
std::vector<Foo> z(x.begin(), x.end());
z.swap(y);
}
This uses the range constructor, which requires only that T
be EmplaceConstructible
, no assignment operator needed! You can then swap the underlying memory without any further copies.
Note that this may result in larger memory usage, since any existing content of y
will persist until the freshly swapped z
goes out of scope. You could try to mitigate this by first doing
y.clear();
y.shrink_to_fit();
although shrink_to_fit()
is only a request, and may not be honoured by your library implementation.
[Live demo]
Why c++ vector inner elements/array are copied when passed by value
C++ allows class types to provide their own code for what it means to be created, copied, moved, and destroyed, and that code is called implicitly, without any obvious function calls. This is called value semantics and it's what C++ uses where other languages resort to things like create_foo(foo)
, foo.clone()
, destroy_foo(foo)
or foo.dispose()
.
Each class can define the following special member functions:
- Constructors, for putting the object into a valid initial state
- A Destructor, for cleaning up responsibly
- A Copy Constructor, for creating a new object that is a duplicate of another
- A Move Constructor, for creating a new object by transferring the data of another
- A Copy Assignment Operator, for duplicating an object into an existing object
- A Move Assignment Operator, for transferring data between two existing objects
These are all functions that you can define to do whatever you want. But they are called implicitly, meaning that users of such a class don't see these function calls in their code, and they expect them to do predictable things. You should make sure that your classes behave predictably by following the Rule of Three/Five/Zero.
There are of course other tools for sharing data, like pass-by-reference, which you already know about.
Lots of classes in the standard library use these special member functions to implement special behaviors that are very useful and help users write safe, correct code. For example:
std::vector
when copied, will always have identical elements, though the underlying array and objects contained will be separate.std::unique_ptr
wraps a resource that has only one owner. To enforce this, it can't be copied.std::shared_ptr
wraps a resource that has many owners. It's not totally clear when to clean up such a resource, so copying ashared_ptr
performs automatic reference counting, and the resource is cleaned up only when the last owner is done with it.
std vector C++ -- deep or shallow copy
You are making a deep copy any time you copy a vector. But if your vector is a vector of pointers you are getting the copy of pointers, not the values are pointed to
For example:
std::vector<Foo> f;
std::vector<Foo> cp = f; //deep copy. All Foo copied
std::vector<Foo*> f;
std::vector<Foo*> cp = f; //deep copy (of pointers), or shallow copy (of objects).
//All pointers to Foo are copied, but not Foo themselves
Copying std::vector of primitive types behavior
Yes, T
's copy constructor must be called. If the copy constructor is trivial, it's effect is the exact same as that of memcpy
, so an implementation is fine to use the latter to implement that copy constructor. From there on, the implementation may decide to use memcpy
to implement the copy constructor of vector
. That decision makes use of the as-if rule: The program's observable behavior remains unchanged, hence we need not actually perform all the copy constructor calls.
On the other hand, does it guaranteed by the standard that it would
call memcpy (or something similar) on primitive types (for
performance issues)?
No, because how a copy constructor is actually implemented is an implementation detail. The standard merely specifies a program's (observable) behavior, and it does that using the notion of copy constructors etc. Optimization is nothing an abstract standard document should worry about, but your vendor. In fact, restraining the definitions of such functions would either incur a huge deficit in optimization, or be outright ignored due to the aforementioned as-if rule.
Related Topics
How to Use Non-Default Delimiters When Reading a Text File with Std::Fstream
Profiler for Visual Studio 2008, C++
Create a Reverse Linkedlist in C++ from a Given Linkedlist
Clang Doesn't See Basic Headers
Initializing Std::String from Char* Without Copy
Does a C/C++ Compiler Optimize Constant Divisions by Power-Of-Two Value into Shifts
Cmake: Failed to Run Msbuild Command: Msbuild.Exe
Reason for Using Non-Type Template Parameter Instead of Regular Parameter
Consistent Pseudo-Random Numbers Across Platforms
Difference Between 'Strcpy' and 'Strcpy_S'
How to Build Google's Protobuf in Windows Using Mingw
Why Does Wide File-Stream in C++ Narrow Written Data by Default
How to Create a Template Function Within a Class? (C++)
Request for Member '...' Is Ambiguous in G++
C++ Template Parameter Type Inference
Why Does a C++ Friend Class Need a Forward Declaration Only in Other Namespaces