Since const reference is pretty much the same as passing by value but without creating a copy (to my understanding). So is there a case where it is needed to create a copy of the variables (so we would need to use pass by value).
There are situations where you don't modify the input, but you still need an internal copy of the input, and then you may as well take the arguments by value. For example, suppose you have a function that returns a sorted copy of a vector:
template <typename V> V sorted_copy_1(V const & v)
{
V v_copy = v;
std::sort(v_copy.begin(), v_copy.end());
return v;
}
This is fine, but if the user has a vector that they never need for any other purpose, then you have to make a mandatory copy here that may be unnecessary. So just take the argument by value:
template <typename V> V sorted_copy_2(V v)
{
std::sort(v.begin(), v.end());
return v;
}
Now the entire process of producing, sorting and returning a vector can be done essentially "in-place".
Less expensive examples are algorithms which consume counters or iterators which need to be modified in the process of the algorithm. Again, taking those by value allows you to use the function parameter directly, rather than requiring a local copy.
It's usually faster to pass basic data types such as ints, floats and pointers by value.
Your function may want to modify the parameter locally, without altering the state of the variable passed in.
C++11 introduces move semantics. To move an object into a function parameter, its type cannot be const reference.
Like so many things, it's a balance.
We pass by const reference to avoid making a copy of the object.
When you pass a const reference, you pass a pointer (references are pointers with extra sugar to make them taste less bitter). And assuming the object is trivial to copy, of course.
To access a reference, the compiler will have to dereference the pointer to get to the content [assuming it can't be inlined and the compiler optimises away the dereference, but in that case, it will also optimise away the extra copy, so there's no loss from passing by value either].
So, if your copy is "cheaper" than the sum of dereferencing and passing the pointer, then you "win" when you pass by value.
And of course, if you are going to make a copy ANYWAY, then you may just as well make the copy when constructing the argument, rather than copying explicitly later.
The best example is probably the Copy and Swap idiom:
C& operator=(C other)
{
swap(*this, other);
return *this;
}
Taking other by value instead of by const reference makes it much easier to write a correct assignment operator that avoids code duplication and provides a strong exception guarantee!
Also passing iterators and pointers is done by value since it makes those algorithms much more reasonable to code, since they can modify their parameters locally. Otherwise something like std::partition would have to immediately copy its input anyway, which is both inefficient and looks silly. And we all know that avoiding silly-looking code is the number one priority:
template<class BidirIt, class UnaryPredicate>
BidirIt partition(BidirIt first, BidirIt last, UnaryPredicate p)
{
while (1) {
while ((first != last) && p(*first)) {
++first;
}
if (first == last--) break;
while ((first != last) && !p(*last)) {
--last;
}
if (first == last) break;
std::iter_swap(first++, last);
}
return first;
}
A const& cannot be changed without a const_cast through the reference, but it can be changed. At any point where code leaves the "analysis range" of your compiler (maybe a function call to a different compilation unit, or through a function pointer it cannot determine the value of at compilation time) it must assume that the value referred to may have changed.
This costs optimization. And it can make it harder to reason about possible bugs or quirks in your code: a reference is non-local state, and functions that operate only on local state and produce no side effects are really easy to reason about. Making your code easy to reason about is a large boon: more time is spent maintaining and fixing code than writing it, and effort spent on performance is fungible (you can spent it where it matters, instead of wasting time on micro optimizations everywhere).
On the other hand, a value requires that the value be copied into local automatic storage, which has costs.
But if your object is cheap to copy, and you don't want the above effect to occur, always take by value as it makes the compilers job of understanding the function easier.
Naturally only when the value is cheap to copy. If expensive to copy, or even if the copy cost is unknown, that cost should be enough to take by const&.
The short version of the above: taking by value makes it easier for you and the compiler to reason about the state of the parameter.
There is another reason. If your object is cheap to move, and you are going to store a local copy anyhow, taking by value opens up efficiencies. If you take a std::string by const&, then make a local copy, one std::string may be created in order to pass thes parameter, and another created for the local copy.
If you took the std::string by value, only one copy will be created (and possibly moved).
For a concrete example:
std::string some_external_state;
void foo( std::string const& str ) {
some_external_state = str;
}
void bar( std::string str ) {
some_external_state = std::move(str);
}
then we can compare:
int main() {
foo("Hello world!");
bar("Goodbye cruel world.");
}
the call to foo creates a std::string containing "Hello world!". It is then copied again into the some_external_state. 2 copies are made, 1 string discarded.
The call to bar directly creates the std::string parameter. Its state is then moved into some_external_state. 1 copy created, 1 move, 1 (empty) string discarded.
There are also certain exception safety improvements caused by this technique, as any allocation happens outside of bar, while foo could throw a resource exhausted exception.
This only applies when perfect forwarding would be annoying or fail, when moving is known to be cheap, when copying could be expensive, and when you know you are almost certainly going to make a local copy of the parameter.
Finally, there are some small types (like int) which the non-optimized ABI for direct copies is faster than the non-optimized ABI for const& parameters. This mainly matters when coding interfaces that cannot or will not be optimized, and is usually a micro optimization.
Related
I want to overload the == operator for a simple struct
struct MyStruct {
public:
int a;
float b;
bool operator==( ) { }
}
All the examples I'm seeing seem to pass the value by reference using a &.
But I really want to pass these structs by value.
Is there anything wrong with me writing this as
bool operator== (MyStruct another) { return ( (a==another.a) && (b==another.b) ); }
It should really not matter expect that you pay the penalty of a copy when you pass by value. This applies if the struct is really heavy. In the simple example you quote, there may not be a big difference.
That being said, passing by const reference makes more sense since it expresses the intent of the overloaded function == clearly. const makes sure that the overloaded function accidentally doesn't modify the object and passing by reference saves you from making a copy. For == operator, there is no need to pass a copy just for comparison purposes.
If you are concerned about consistency, it's better to switch the other pass by value instances to pass by const ref.
While being consistent is laudable goal, one shouldn't overdo it. A program containing only 'A' characters would be very consistent, but hardly useful. Argument passing mechanism is not something you do out of consistency, it is a technical decision based on certain technical aspects.
For example, in your case, passing by value could potentially lead to better performance, since the struct is small enough and on AMD64 ABI (the one which is used on any 64bit Intel/AMD chip) it will be passed in a register, thus saving time normally associated with dereferencing.
On the hand, in your case, it is reasonable to assume that the function will be inlined, and passing scheme will not matter at all (since it won't be passed). This is proven by codegen here (no call to operator== exist in generated assembly): https://gcc.godbolt.org/z/G7oEgE
Motivation:
I'm trying to transfer a std::vector<std::unique_ptr<some_type>> to a different thread, via a lambda capture.
Since I need the vector to not be cleaned up when the function goes out of scope, I need to take it by value (and not by reference).
Since it's a vector of unique_ptrs, I need to move (and not copy) it into the capture.
I'm using a generalized lambda capture to move the vector while capturing.
Minimal program to illustrate the concept:
auto create_vector(){
std::vector<std::unique_ptr<int>> new_vector{};
new_vector.push_back(std::make_unique<int>(5));
return std::move(new_vector);
}
int main() {
const auto vec_const = create_vector();
[vec=std::move(vec_const)](){
std::cout << "lambda, vec size: " << vec.size() << std::endl;
}();
}
Issue:
If I'm using a const local vector, compilation fails due to attempting to copy the unique_ptrs.
However if I remove the const qualifier, the code compiles and runs well.
auto vec_const = create_vector();
Questions:
What's the reason for this? Does being const disable the "movability" of the vector? Why?
How would I ensure the constness of a vector in such a scenario?
Follow-up:
The comments and answers mention that a const type can't be moved from. Sounds reasonable, however the the compiler errors fail to make it clear. In this case I would expect one of two things:
The std::move(vec_const) should throw an error regarding moving from const (casting it to rvalue) being impossible.
The vector move-constructor telling me that it refuses to accept const rvalues.
Why don't those happen? Why does instead the assignment seems to just try to copy the unique_ptrs inside the vector (which is what I'd expect from the vectors copy-constructor)?
Moving is a disruptive operation: you conceptually change the content of the thing you move from.
So yes: a const object can (and should) not be moved from. That would change the original object, which makes its constness void.
In this case, vector has no vector(const vector&&), only vector(vector &&) (move constructor) and vector(const vector &) (copy constructor).
Overload resolution will only bind a call with const vector argument to the latter (lest const-correctness would be violated), so this will result in copying the contents.
I agree: error reporting sucks. It's hard to engineer an error report about vector when you hit a problem with unique_ptr. That's why the whole tail of required from ...., required from ... obliterates the view.
From your question, and your code, I can tell that you don't fully grasp the move semantics stuff:
you shouldn't move into a return value; a return value is already an rvalue, so there's no point.
std::move does not really move anything, it only changes the qualifier of the variable you want to 'move from', so that the right receiver can be selected (using 'binding' rules). It is the receiving function that actually changes the contents of the original object.
When you are moving something from A to B, then act of moving must necessarily mean that A gets modified, since after the move A may no longer have whatever was in A, originally. This is the whole purpose of move semantics: to provide an optimal implementation since the moved-from object is allowed to be modified: its contents getting transferred in some fast and mysterious way into B, leaving A in some valid, but unspecified, state.
Consequently, by definition, A cannot be const.
I wonder how c++ stl predicate is implemented? For example in copy_if()
http://www.cplusplus.com/reference/algorithm/copy_if/
According to Effective STL, predicate is passed by value. For the following code for int,
struct my_predicate{
int var_1;
float var_2;
bool operator()(const int& arg){
// some processing here
}
}
How is copy_if() implemented regarding to passing value of my_predicate? There are var_1 and var_2 here. For other predicates, there may be different variables in the struct.
If passing by reference or pointer, that is very reasonable to me.
Thanks a lot!
(I hope I'm not misunderstanding your question.)
The reason why it can be passed by value is that the 'my_predicate' struct has an implicit copy constructor automatically generated by the compiler. You can pass it by value because it has a copy constructor.
In practice, It is very likely the compiler will optimise away the copy. In fact it is very likely the compiler will optimise away the entire predicate object and for example in the case of std::copy_if reduce the code to the equivalent of a for loop + if statement.
By convention predicates are passed by value. They are not meant to be heavy weight objects and for small objects even if the entire predicate isn't optimised away, it is faster to pass by value anyway.
Also generally you cannot pass temporary values by non-const reference (let alone pointer) so:
std::copy_if(begin(..),end(..),my_predicate{});
would not compile as your predicate is not a const function. With pass by value you can get away with this.
I have the following function:
void read_int(std::vector<int> &myVector)
Which allows me to fill myVector through it reference. It is used like this:
std::vector<int> myVector;
read_int(myVector);
I want to refactor a bit the code (keeping the original function) to in the end have this:
auto myVector = read_int(); // auto is std::vector<int>
What would be the best intermediate function to achieve this?
It seems to me that the following straight-forward answer is suboptimal:
std::vector<int> read_int() {
std::vector<int> myVector_temp;
read_int(myVector_temp);
return myVector_temp;
}
The obvious answer is correct, and basically optimal.
void do_stufF(std::vector<int>& on_this); // (1)
std::vector<int> do_stuff_better() { // (2)
std::vector<int> myVector_temp; // (3)
do_stuff(myVector_temp); // (4)
return myVector_temp; // (5)
}
At (3) we create a named return value in automatic storage (on the stack).
At (5) we only ever return the named return value from the function, and we never return anything else but that named return value anywhere else in the function.
Because of (3) and (5), the compiler is allowed to (and most likely will) elide the existence of the myVector_temp object. It will directly construct the return value of the function, and call it myVector_temp. It still needs there to be an existing move or copy constructor, but it does not call it.
On the other end, when calling do_stuff_better, some compilers can also elide the assignment at call:
std::vector<int> bob = do_stuff_better(); // (6)
The compiler is allowed to effectively pass a "pointer to bob" and tell do_stuff_better() to construct its return value in bob's location, eliding this copy construction as well (well, it can arrange how the call occurs such that the location that do_stuff_better() is asked to construct its return value in is the same as the location of bob).
And in C++11, even if the requirements for both elisions are not met, or the compiler chooses not to use them, in both cases a move must be done instead of a copy.
At line (5) we are returning a locally declared automatic storage duration variable in a plain and simple return statement. This makes the return an implicit move if not elided.
At line (6), the function returns an unnamed object, which is an rvalue. When bob is constructed from it, it move-constructs.
moveing a std::vector consists of copying the value of ~3 pointers, and then zeroing the source, regardless of how big the vector is. No elements need be copied or moved.
Both of the above elisions, where we remove the named local variable within do_stuff_better(), and we remove the return value of do_stuff_better() and instead directly construct bob, are somewhat fragile. Learning the rules under which your compiler is allowed to do those elisions, and also the situations where your compiler actually does the elisions, is worthwhile.
As an example of how it is fragile, if you had a branch where you did a return std::vector<int>() in your do_stuff_better() after checking an error state, the in-function elision would probably be blocked.
Even if elision is blocked or your compiler doesn't implement it for a case, the fact that the container is move'd means that the run time costs are going to be minimal.
I think, you have to read more about move semantics (link to Google query, there are a lot of papers on this - just choose one).
In short, in C++ all STL containers are written in such way, that returning them from function will cause their contents to be moved from the returned value (so called right-hand reference) to the variable you are assigning it to. In effect you'll only copy a few fields of the std::vector instead of its data. That's a lot faster than copying its contents.
I saw code somewhere in which someone decided to copy an object and subsequently move it to a data member of a class. This left me in confusion in that I thought the whole point of moving was to avoid copying. Here is the example:
struct S
{
S(std::string str) : data(std::move(str))
{}
};
Here are my questions:
Why aren't we taking an rvalue-reference to str?
Won't a copy be expensive, especially given something like std::string?
What would be the reason for the author to decide to make a copy then a move?
When should I do this myself?
Before I answer your questions, one thing you seem to be getting wrong: taking by value in C++11 does not always mean copying. If an rvalue is passed, that will be moved (provided a viable move constructor exists) rather than being copied. And std::string does have a move constructor.
Unlike in C++03, in C++11 it is often idiomatic to take parameters by value, for the reasons I am going to explain below. Also see this Q&A on StackOverflow for a more general set of guidelines on how to accept parameters.
Why aren't we taking an rvalue-reference to str?
Because that would make it impossible to pass lvalues, such as in:
std::string s = "Hello";
S obj(s); // s is an lvalue, this won't compile!
If S only had a constructor that accepts rvalues, the above would not compile.
Won't a copy be expensive, especially given something like std::string?
If you pass an rvalue, that will be moved into str, and that will eventually be moved into data. No copying will be performed. If you pass an lvalue, on the other hand, that lvalue will be copied into str, and then moved into data.
So to sum it up, two moves for rvalues, one copy and one move for lvalues.
What would be the reason for the author to decide to make a copy then a move?
First of all, as I mentioned above, the first one is not always a copy; and this said, the answer is: "Because it is efficient (moves of std::string objects are cheap) and simple".
Under the assumption that moves are cheap (ignoring SSO here), they can be practically disregarded when considering the overall efficiency of this design. If we do so, we have one copy for lvalues (as we would have if we accepted an lvalue reference to const) and no copies for rvalues (while we would still have a copy if we accepted an lvalue reference to const).
This means that taking by value is as good as taking by lvalue reference to const when lvalues are provided, and better when rvalues are provided.
P.S.: To provide some context, I believe this is the Q&A the OP is referring to.
To understand why this is a good pattern, we should examine the alternatives, both in C++03 and in C++11.
We have the C++03 method of taking a std::string const&:
struct S
{
std::string data;
S(std::string const& str) : data(str)
{}
};
in this case, there will always be a single copy performed. If you construct from a raw C string, a std::string will be constructed, then copied again: two allocations.
There is the C++03 method of taking a reference to a std::string, then swapping it into a local std::string:
struct S
{
std::string data;
S(std::string& str)
{
std::swap(data, str);
}
};
that is the C++03 version of "move semantics", and swap can often be optimized to be very cheap to do (much like a move). It also should be analyzed in context:
S tmp("foo"); // illegal
std::string s("foo");
S tmp2(s); // legal
and forces you to form a non-temporary std::string, then discard it. (A temporary std::string cannot bind to a non-const reference). Only one allocation is done, however. The C++11 version would take a && and require you to call it with std::move, or with a temporary: this requires that the caller explicitly creates a copy outside of the call, and move that copy into the function or constructor.
struct S
{
std::string data;
S(std::string&& str): data(std::move(str))
{}
};
Use:
S tmp("foo"); // legal
std::string s("foo");
S tmp2(std::move(s)); // legal
Next, we can do the full C++11 version, that supports both copy and move:
struct S
{
std::string data;
S(std::string const& str) : data(str) {} // lvalue const, copy
S(std::string && str) : data(std::move(str)) {} // rvalue, move
};
We can then examine how this is used:
S tmp( "foo" ); // a temporary `std::string` is created, then moved into tmp.data
std::string bar("bar"); // bar is created
S tmp2( bar ); // bar is copied into tmp.data
std::string bar2("bar2"); // bar2 is created
S tmp3( std::move(bar2) ); // bar2 is moved into tmp.data
It is pretty clear that this 2 overload technique is at least as efficient, if not more so, than the above two C++03 styles. I'll dub this 2-overload version the "most optimal" version.
Now, we'll examine the take-by-copy version:
struct S2 {
std::string data;
S2( std::string arg ):data(std::move(x)) {}
};
in each of those scenarios:
S2 tmp( "foo" ); // a temporary `std::string` is created, moved into arg, then moved into S2::data
std::string bar("bar"); // bar is created
S2 tmp2( bar ); // bar is copied into arg, then moved into S2::data
std::string bar2("bar2"); // bar2 is created
S2 tmp3( std::move(bar2) ); // bar2 is moved into arg, then moved into S2::data
If you compare this side-by-side with the "most optimal" version, we do exactly one additional move! Not once do we do an extra copy.
So if we assume that move is cheap, this version gets us nearly the same performance as the most-optimal version, but 2 times less code.
And if you are taking say 2 to 10 arguments, the reduction in code is exponential -- 2x times less with 1 argument, 4x with 2, 8x with 3, 16x with 4, 1024x with 10 arguments.
Now, we can get around this via perfect forwarding and SFINAE, allowing you to write a single constructor or function template that takes 10 arguments, does SFINAE to ensure that the arguments are of appropriate types, and then moves-or-copies them into the local state as required. While this prevents the thousand fold increase in program size problem, there can still be a whole pile of functions generated from this template. (template function instantiations generate functions)
And lots of generated functions means larger executable code size, which can itself reduce performance.
For the cost of a few moves, we get shorter code and nearly the same performance, and often easier to understand code.
Now, this only works because we know, when the function (in this case, a constructor) is called, that we will be wanting a local copy of that argument. The idea is that if we know that we are going to be making a copy, we should let the caller know that we are making a copy by putting it in our argument list. They can then optimize around the fact that they are going to give us a copy (by moving into our argument, for example).
Another advantage of the 'take by value" technique is that often move constructors are noexcept. That means the functions that take by-value and move out of their argument can often be noexcept, moving any throws out of their body and into the calling scope (who can avoid it via direct construction sometimes, or construct the items and move into the argument, to control where throwing happens). Making methods nothrow is often worth it.
This is probably intentional and is similar to the copy and swap idiom. Basically since the string is copied before the constructor, the constructor itself is exception safe as it only swaps (moves) the temporary string str.
You don't want to repeat yourself by writing a constructor for the move and one for the copy:
S(std::string&& str) : data(std::move(str)) {}
S(const std::string& str) : data(str) {}
This is much boilerplate code, especially if you have multiple arguments. Your solution avoids that duplication on the cost of an unnecessary move. (The move operation should be quite cheap, however.)
The competing idiom is to use perfect forwarding:
template <typename T>
S(T&& str) : data(std::forward<T>(str)) {}
The template magic will choose to move or copy depending on the parameter that you pass in. It basically expands to the first version, where both constructor were written by hand. For background information, see Scott Meyer's post on universal references.
From a performance aspect, the perfect forwarding version is superior to your version as it avoids the unnecessary moves. However, one can argue that your version is easier to read and write. The possible performance impact should not matter in most situations, anyway, so it seems to be a matter of style in the end.