I've heard that you should always prefer "pass by value" in C++11 because of the introduction of move semantics. I wanted to see what the hype was all about and constructed a test case. First my class:
struct MyClass {
MyClass() { }
MyClass(const MyClass&) { std::cout << "Copy construct" << std::endl; }
MyClass(MyClass&&) { std::cout << "Move construct" << std::endl; }
~MyClass() { }
};
And the test harness:
class Test
{
public:
void pass_by_lvalue_ref(const MyClass& myClass)
{
_MyClass.push_back(myClass);
}
void pass_by_rvalue_ref(MyClass&& myClass)
{
_MyClass.push_back(std::move(myClass));
}
void pass_by_value(MyClass myClass)
{
_MyClass.push_back(std::move(myClass));
}
private:
std::vector<MyClass> _MyClass;
};
Presumably, pass_by_value should outperform pass_by_lvalue_ref and pass_by_rvalue_ref (together, not separately).
int main()
{
MyClass myClass;
Test Test;
std::cout << "--lvalue_ref--\n";
Test.pass_by_lvalue_ref(myClass);
std::cout << "--rvalue_ref--\n";
Test.pass_by_rvalue_ref(MyClass{});
std::cout << "--value - lvalue--\n";
Test.pass_by_value(myClass);
std::cout << "--value - rvalue--\n";
Test.pass_by_value(MyClass{});
}
This is my output on GCC 4.9.2 with -O2:
--lvalue_ref--
Copy construct
--rvalue_ref--
Move construct
Copy construct
--value - lvalue--
Copy construct
Move construct
Copy construct
Copy construct
--value - rvalue--
Move construct
As you can see, the non-pass_by_value functions requires a total of 2 copy constructs and 1 move construct. The pass_by_value function requires a total of 3 copy constructs and 2 move constructs. It looks like that, as expected, the object is going to be copied anyway, so why does everyone say pass by value?
First, your reporting is entirely flawed. Each of your functions pushes back to the same vector. When that vector runs out of capacity (which depends upon how many items you've inserted so far), it is going to trigger a re-allocation which will require more moves and/or copies than an insertion which doesn't trigger an allocation.
Second, std::vector::push_back has a strong exception safety guarantee. So if your move constructor is not noexcept, it will not use it (unless the class is non-copyable). It will use the copy constructor instead.
Third,
I've heard that you should always prefer "pass by value" in C++11
because of the introduction of move semantics.
I'm pretty sure you didn't hear that from any reputable source. Or are actually inappropriately paraphrasing what was actually said. But I don't have the source of the quote. What is usually advised is actually that if you are going to copy your arguments in your function anyway, don't. Just do it in the parameter list (via pass by value). This will allow your function to move r-value arguments straight to their destination. When you pass l-values, they will be copied, but you were going to do that anyway.
If you are going to make an internal copy, then passing by value will do exactly one move construct more than the pair of overloads (pass by rvalue ref)+(pass by const lvalue ref).
If move construct is cheap, this is a small amount of runtime overhead in exchange for less compile time and code maintenance overhead.
The idiom is "Want speed? Making a copy anyhow? Pass by value, instead of by const lvalue reference." in reality.
Finally, your benchmark is flawed as you failed to reserve(enough) before your push backs. Reallocation can cause extra operations. Oh, and make your move constructor noexcept, as conforming libraries will prefer a copy to a move if move can throw in many situations.
Related
Can somebody explain why everybody passes std::unique_ptr by value instead of by rvalue reference?
From what I've observed, this required an additional move constructor to be invoked.
Here's an example of a class holding a "pointer". It takes 3 move-ctor calls to take it by value, versus 2 calls to take it by reference:
#include <memory>
#include <iostream>
class pointer {
public:
pointer()
{ std::cerr << "ctor" << std::endl; }
pointer(const pointer&)
{ std::cerr << "copy-ctor" << std::endl; }
pointer& operator=(const pointer&)
{ std::cerr << "copy-assignment" << std::endl; return *this; }
pointer(pointer&&)
{ std::cerr << "move-ctor" << std::endl; }
pointer& operator=(pointer&&)
{ std::cerr << "move-assignment" << std::endl; return *this; }
~pointer()
{ std::cerr << "dtor" << std::endl; }
};
class A {
public:
// V1
A(pointer _ptr) : ptr(std::move(_ptr)) {}
// V2
A(pointer&& _ptr) : ptr(std::move(_ptr)) {}
private:
pointer ptr;
};
int main() {
// Three calls to move-ctor versus two calls if pass by rvalue reference
auto ptr = pointer();
A a(std::move(ptr));
// Two calls to move-ctor always
A a(pointer{});
}
Passing a unique_ptr by reference, rvalue or otherwise, doesn't actual move anything, so you can't know by just looking at the function declaration if a move will happen.
Passing a unique_ptr by value on the other hand guarantees that the passed in pointer will be moved from, so without even have to look at the documentation you know calling that function releases you from the pointers' ownership.
For the same reason people pass int instead of const int&.
std::unique_ptr is just an RAII wrapper around a single pointer value, so moving it is just copying a single register width value, then zeroing the source. That's so trivial there's no real benefit to avoiding the move. After all, the cost to pass the reference (when not inlined) is the cost of passing a pointer too, so passing by reference can be less efficient (because if not inlined, it has to follow the reference to the real memory, then pull out the value from there; the top of the stack is likely in L1 cache, who knows if the place it's stored is?).
In practice, much of this will be inlined with optimizations enabled, and both approaches would get the same result. Passing by value is a good default when there's no benefit to passing by reference, so why not do it that way?
why everybody passes the std::unique_ptr by value instead of rvalue reference?
It may be more common, but it's not "everybody".
The drawback of std::unique_ptr&& parameter is that it doesn't explicitly communicate to the caller whether the pointer will be moved from or not. It might always move, or it might depend on some condition. You would have to know the implementation or at least API documentation to know for sure. The corresponding benefit of std::unique_ptr parameter is that it alone tells the reader of the declaration that the function will take ownership of the pointer. For this reason, it may be a good choice to use std::unique_ptr parameter and probably part of the reason why it's more common.
The benefit of std::unique_ptr&& is avoiding the extra move. However, moving of a std::unique_ptr is a very fast operation. It's insignificant compared for example to the memory allocation itself. In most cases, it simply doesn't matter.
The difference between the two is fairly subtle. std::unique_ptr&& parameter may be considered in a case where you've measured the move to have significant cost. Which is not very common. Or in cases where your API may be used in cases where that cost could be significant. It's hard to prove that this won't ever happen if you're writing a public API, so it is a more likely argument to use.
Why in the example code below, object is copied twice? According documentation constructor of thread class copies all arguments to thread-local storage so we have reason for the first copy. What about second?
class A {
public:
A() {cout << "[C]" << endl;}
~A() {cout << "[~D]" << endl;}
A(A const& src) {cout << "[COPY]" << endl;}
A& operator=(A const& src) {cout << "[=}" << endl; return *this;}
void operator() () {cout << "#" << endl;}
};
void foo()
{
A a;
thread t{a};
t.join();
}
Output from above:
[C]
[COPY]
[COPY]
[~D]
#
[~D]
[~D]
Edit:
Well yes, after adding move constructor:
A(A && src) {cout << "[MOVE]" << endl;}
The output is like this:
[C]
[COPY]
[MOVE]
[~D]
#
[~D]
[~D]
For anything you want to move or avoid copies, prefer move constructors and std::move.
But Why doesn't this happen automatically for me?
Move in C++ is conservative. It generally will only move if you explicitly write std::move(). This was done because move semantics, if extended beyond very explicit circumstances, might break older code. Automatic-moves are often restricted to very careful set of circumstances for this reason.
In order to avoid copies in this situation, you need to shift a around by using std::move(a) (even when passing it into std::thread). The reason it makes a copy the first time around is because std::thread can't guarantee that the value will exist after you have finished constructing the std::thread (and you haven't explicitly moved it in). Thusly, it will do the safe thing and make a copy (not take a reference/pointer to what you passed in and store it: the code has no idea whether or not you'll keep it alive or not).
Having both a move constructor and using std::move will allow the compiler to maximally and efficiently move your structure. If you're using VC++ (with the CTP or not), you must explicitly write the move constructor, otherwise MSVC will (even sometimes erroneously) declare and use a Copy constructor.
The object is copied twice because the object cannot be moved. The standard does not require this, but it is legitimate behavior.
What's happening inside of the implementation is that it seems to be doing a decay_copy of the parameters, as required by the standard. But it doesn't do the decay_copy into the final destination; it does it into some internal, possibly stack, storage. Then it moves the objects from that temporary storage to the final location within the thread. Since your type is not moveable, it must perform a copy.
If you make your type moveable, you'll find that the second copy becomes a move.
Why might an implementation do this, rather than just copying directly into the final destination? There could be any number of implementation-dependent reasons. It may have just been simpler to build a tuple of the function+parameters on the stack, then move that into the eventual destination.
try with: thread t{std::move(a)};
Consider the below code, where a composing class with another class as its member is being instantiated:
class CopyAble {
private:
int mem1;
public:
CopyAble(int n1) : mem1(n1) {
cout << "Inside the CopyAble constructor" << endl;
}
CopyAble(const CopyAble& obj) {
cout << "Inside the CopyAble copy constructor" << endl;
this->mem1 = obj.mem1;
return *this;
}
CopyAble& operator=(const CopyAble& obj) {
cout << "Inside the CopyAble assignment constructor" << endl;
this->mem1 = obj.mem1;
}
~CopyAble() {};
};
class CopyAbleComposer {
private:
CopyAble memObj;
public:
CopyAbleComposer(CopyAble m1) : memObj(m1) {
cout << "Composing the composer" << endl;
}
~CopyAbleComposer() {}
};
int main()
{
CopyAble ca(10);
CopyAbleComposer cac(ca);
return 0;
}
When I run this, I get the output:
Inside the CopyAble constructor
Inside the CopyAble copy constructor
Inside the CopyAble copy constructor
Composing the composer
Which means that the CopyAble copy constructor is being run twice - once when the CopyAble object is passed into the CopyAbleComposer constructor, and again when the initializer memObj(m1) runs.
Is this an idiomatic use of the copy constructor? It seems very inefficient that the copy constructor runs twice when we try to initialize a member object with a passed-in object of the same type, and it seems like a trap a lot of C++ programmers can easily fall into without realizing it.
EDIT: I don't think this is a duplicate of the question regarding passing a reference into the copy constructor. Here, we are being forced to pass a reference into a regular constructor to avoid duplicate object creation, my question was that is this generally known that class constructors in C++ should have objects passed in by reference to avoid this kind of duplicate copy?
You should accept CopyAble by reference at CopyAbleComposer(CopyAble m1), otherwise a copy constructor will be called to construct an argument. You should also mark it as explicit to avoid accidental invocations:
explicit CopyAbleComposer(const CopyAble & m1)
Pass-by-value and the associated copying is a pretty widely known property of C++. Actually, in the past C++ was criticized for this gratuitious copying, which happened silently, was hard to avoid and could lead to decreased performance. This is humorously mentioned e.g. here:
You accidentally create a dozen instances of yourself and shoot them all in the foot. Providing emergency medical assistance is impossible since you can't tell which are bitwise copies and which are just pointing at others and saying, "That's me, over there."
C++98
When any function/method is declared to receive an argument by value, this sort of copying happens. It doesn't matter if it's a constructor, a "stand-alone" function or a method. To avoid this, use a const reference:
CopyAbleComposer(const CopyAble& m1) : memObj(m1)
{
...
}
Note: even if you rearrange your code as below, one copy always remains. This has been a major deficiency in C++ for a long time.
CopyAbleComposer cac(CopyAble(10)); // initializing mem1 by a temporary object
C++11
C++11 introduced move semantics, which replaces the additional copy by a "move" operation, which is supposed to be more efficient than copy: in the common case where an object allocates memory dynamically, "move" only reassigns some pointers, while "copy" allocates and deallocates memory.
To benefit from optimization offered by move semantics, you should undo the "optimization" you maybe did for C++98, and pass arguments by value. In addition, when initializing the mem1 member, you should invoke the move constructor:
CopyAbleComposer(CopyAble m1) : memObj(std::move(m1)) {
cout << "Composing the composer" << endl;
}
Finally, you should implement the move constructor:
CopyAble(CopyAble&& obj) {
cout << "Inside the CopyAble move constructor" << endl;
this->mem1 = obj.mem1;
}
Then you should see that the "copy" message doesn't appear, and is replaced by the "move" message.
See this question for more details.
Note: In all these examples, the CopyAble objects are assumed to be much more complex, with copy and move constructors doing non-trivial work (typically, resource management). In modern C++, resource management is considered a separate concern, in the context of separation of concerns. That is, any class that needs a non-default copy or move constructor, should be as small as possible. This is also called the Rule of Zero.
Why in the example code below, object is copied twice? According documentation constructor of thread class copies all arguments to thread-local storage so we have reason for the first copy. What about second?
class A {
public:
A() {cout << "[C]" << endl;}
~A() {cout << "[~D]" << endl;}
A(A const& src) {cout << "[COPY]" << endl;}
A& operator=(A const& src) {cout << "[=}" << endl; return *this;}
void operator() () {cout << "#" << endl;}
};
void foo()
{
A a;
thread t{a};
t.join();
}
Output from above:
[C]
[COPY]
[COPY]
[~D]
#
[~D]
[~D]
Edit:
Well yes, after adding move constructor:
A(A && src) {cout << "[MOVE]" << endl;}
The output is like this:
[C]
[COPY]
[MOVE]
[~D]
#
[~D]
[~D]
For anything you want to move or avoid copies, prefer move constructors and std::move.
But Why doesn't this happen automatically for me?
Move in C++ is conservative. It generally will only move if you explicitly write std::move(). This was done because move semantics, if extended beyond very explicit circumstances, might break older code. Automatic-moves are often restricted to very careful set of circumstances for this reason.
In order to avoid copies in this situation, you need to shift a around by using std::move(a) (even when passing it into std::thread). The reason it makes a copy the first time around is because std::thread can't guarantee that the value will exist after you have finished constructing the std::thread (and you haven't explicitly moved it in). Thusly, it will do the safe thing and make a copy (not take a reference/pointer to what you passed in and store it: the code has no idea whether or not you'll keep it alive or not).
Having both a move constructor and using std::move will allow the compiler to maximally and efficiently move your structure. If you're using VC++ (with the CTP or not), you must explicitly write the move constructor, otherwise MSVC will (even sometimes erroneously) declare and use a Copy constructor.
The object is copied twice because the object cannot be moved. The standard does not require this, but it is legitimate behavior.
What's happening inside of the implementation is that it seems to be doing a decay_copy of the parameters, as required by the standard. But it doesn't do the decay_copy into the final destination; it does it into some internal, possibly stack, storage. Then it moves the objects from that temporary storage to the final location within the thread. Since your type is not moveable, it must perform a copy.
If you make your type moveable, you'll find that the second copy becomes a move.
Why might an implementation do this, rather than just copying directly into the final destination? There could be any number of implementation-dependent reasons. It may have just been simpler to build a tuple of the function+parameters on the stack, then move that into the eventual destination.
try with: thread t{std::move(a)};
When I initialize a STL container such as a list< vector<char> > using e.g. my_list.push_back(vector<char>(5000, 'T')) is this copied after construction? Or does the compiler invoke the constructor inside list< vector<char> > itself?
In C++03 push_back is defined as void push_back(const T& x);. That means that you are constructing a vector and a const reference to such temporal is being passed to the list. Then the list internally invokes the copy constructor in order to store a copy of such element.
In C++11 there is an extra definition for void push_back(T&& x); that takes an rvalue reference to your temporal vector, and would result in the move constructor being called internally to initialize the copy held by the list.
Compilers are smart. Really smart. In this case, there is an optimization called "copy elision." The C++ standard allows the compiler to omit a copy when a temporary object is used to initialize an object of the same type and the copy constructor of said object has no side effects.
This is in the same class of optimizations as the more popular "as if" rule. That rule allows the compiler to get away with nearly anything it wants, as long as the observable behavior of the resulting program is the same "as if" the standard had been followed exactly.
Here is an example program. On gcc 4.4.5 with both -O0 and -O3 this code results in a "1" being printed. I think that GCC is wrong here... some compilers will output "2" indicating a copy took place. This is where things get tricky in trying to detect behavior that is supposed to be undetectable. In one of those compilers, the only way to tell will be to dive into the resulting assembly.
#include <iostream>
struct elision
{
explicit elision(int i) : v(i) {
}
elision(elision const ©) : v(copy.v+1) {
}
int v;
};
int main()
{
elision e(elision(1));
std::cout << e.v << std::endl;
return 0;
}