Do const and reference in function parameters cause unnecessary casts? [duplicate] - c++

I have some pre-C++11 code in which I use const references to pass large parameters like vector's a lot. An example is as follows:
int hd(const vector<int>& a) {
return a[0];
}
I heard that with new C++11 features, you can pass the vector by value as follows without performance hits.
int hd(vector<int> a) {
return a[0];
}
For example, this answer says
C++11's move semantics make passing and returning by value much more attractive even for complex objects.
Is it true that the above two options are the same performance-wise?
If so, when is using const reference as in option 1 better than option 2? (i.e. why do we still need to use const references in C++11).
One reason I ask is that const references complicate deduction of template parameters, and it would be a lot easier to use pass-by-value only, if it is the same with const reference performance-wise.

The general rule of thumb for passing by value is when you would end up making a copy anyway. That is to say that rather than doing this:
void f(const std::vector<int>& x) {
std::vector<int> y(x);
// stuff
}
where you first pass a const-ref and then copy it, you should do this instead:
void f(std::vector<int> x) {
// work with x instead
}
This has been partially true in C++03, and has become more useful with move semantics, as the copy may be replaced by a move in the pass-by-val case when the function is called with an rvalue.
Otherwise, when all you want to do is read the data, passing by const reference is still the preferred, efficient way.

There is a big difference. You will get a copy of a vector's internal array unless it was about to die.
int hd(vector<int> a) {
//...
}
hd(func_returning_vector()); // internal array is "stolen" (move constructor is called)
vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8};
hd(v); // internal array is copied (copy constructor is called)
C++11 and the introduction of rvalue references changed the rules about returning objects like vectors - now you can do that (without worrying about a guaranteed copy). No basic rules about taking them as argument changed, though - you should still take them by const reference unless you actually need a real copy - take by value then.

C++11's move semantics make passing and returning by value much more attractive even for complex objects.
The sample you give, however, is a sample of pass by value
int hd(vector<int> a) {
So C++11 has no impact on this.
Even if you had correctly declared 'hd' to take an rvalue
int hd(vector<int>&& a) {
it may be cheaper than pass-by-value but performing a successful move (as opposed to a simple std::move which may have no effect at all) may be more expensive than a simple pass-by-reference. A new vector<int> must be constructed and it must take ownership of the contents of a. We don't have the old overhead of having to allocate a new array of elements and copy the values over, but we still need to transfer the data fields of vector.
More importantly, in the case of a successful move, a would be destroyed in this process:
std::vector<int> x;
x.push(1);
int n = hd(std::move(x));
std::cout << x.size() << '\n'; // not what it used to be
Consider the following full example:
struct Str {
char* m_ptr;
Str() : m_ptr(nullptr) {}
Str(const char* ptr) : m_ptr(strdup(ptr)) {}
Str(const Str& rhs) : m_ptr(strdup(rhs.m_ptr)) {}
Str(Str&& rhs) {
if (&rhs != this) {
m_ptr = rhs.m_ptr;
rhs.m_ptr = nullptr;
}
}
~Str() {
if (m_ptr) {
printf("dtor: freeing %p\n", m_ptr)
free(m_ptr);
m_ptr = nullptr;
}
}
};
void hd(Str&& str) {
printf("str.m_ptr = %p\n", str.m_ptr);
}
int main() {
Str a("hello world"); // duplicates 'hello world'.
Str b(a); // creates another copy
hd(std::move(b)); // transfers authority for b to function hd.
//hd(b); // compile error
printf("after hd, b.m_ptr = %p\n", b.m_ptr); // it's been moved.
}
As a general rule:
Pass by value for trivial objects,
Pass by value if the destination needs a mutable copy,
Pass by value if you always need to make a copy,
Pass by const reference for non-trivial objects where the viewer only needs to see the content/state but doesn't need it to be modifiable,
Move when the destination needs a mutable copy of a temporary/constructed value (e.g. std::move(std::string("a") + std::string("b"))).
Move when you require locality of the object state but want to retain existing values/data and release the current holder.

Remember that if you are not passing in an r-value, then passing by value would result in a full blown copy. So generally speaking, passing by value could lead to a performance hit.

Your example is flawed. C++11 does not give you a move with the code that you have, and a copy would be made.
However, you can get a move by declaring the function to take an rvalue reference, and then passing one:
int hd(vector<int>&& a) {
return a[0];
}
// ...
std::vector<int> a = ...
int x = hd(std::move(a));
That's assuming that you won't be using the variable a in your function again except to destroy it or to assign to it a new value. Here, std::move casts the value to an rvalue reference, allowing the move.
Const references allow temporaries to be silently created. You can pass in something that is appropriate for an implicit constructor, and a temporary will be created. The classic example is a char array being converted to const std::string& but with std::vector, a std::initializer_list can be converted.
So:
int hd(const std::vector<int>&); // Declaration of const reference function
int x = hd({1,2,3,4});
And of course, you can move the temporary in as well:
int hd(std::vector<int>&&); // Declaration of rvalue reference function
int x = hd({1,2,3,4});

Related

Is it possible to avoid a copy when returning an argument from a function?

Suppose I have value type with some in-place operation. For example, something like this:
using MyType = std::array<100, int>;
void Reverse(MyType &value) {
std::reverse(value.begin(), value.end());
}
(The type and operation can be more complicated, but the point is the operation works in-place and the type is trivially copyable and trivially destructible. Note that MyType is large enough to care about avoiding copies, but small enough that it probably doesn't make sense to allocate on the heap, and since it contains only primitives, it doesn't benefit from move semantics.)
I usually find it helpful to also define a helper function that doesn't change the value in-place, but returns a copy with the operation applied to it. Among other things, that enables code like this:
MyType value = Reversed(SomeFunction());
Considering that Reverse() operates in-place, it should be logically possible to calculate value without copying the result from SomeFunction(). How can I implement Reversed() to avoid unnecessary copies? I'm willing to define Reversed() as an inline function in a header if that's what's necessary to enable this optimization.
I can think of two ways to implement this:
inline MyType Reversed1(const MyType &value) {
MyType result = value;
Reverse(result);
return result;
}
This benefits from return-value optimization but only after the argument value has been copied to result.
inline MyType Reversed2(MyType value) {
Reverse(value);
return value;
}
This might require the caller to copy the argument, except if it's already an rvalue, but I don't think return-value optimization is enabled this way (or is it?) so there's a copy upon return.
Is there a way to implemented Reversed() that avoids copies, ideally in a way that it's guaranteed by recent C++ standards?
If you do want to reverse the string in-place so that the change to the string you send in as an argument is visible at the call site and you also want to return it by value, you have no option but to copy it. They are two separate instances.
One alternative: Return the input value by reference. It'll then reference the same object that you sent in to the function:
MyType& Reverse(MyType& value) { // doesn't work with r-values
std::reverse(std::begin(value), std::end(value));
return value;
}
MyType Reverse(MyType&& value) { // r-value, return a copy
std::reverse(std::begin(value), std::end(value));
return std::move(value); // moving doesn't really matter for ints
}
Another alternative: Create the object you return in-place. You'll then return a separate instance with RVO in effect. No moves or copies. It'll be a separate instance from the one you sent in to the function though.
MyType Reverse(const MyType& value) {
// Doesn't work with `std::array`s:
return {std::rbegin(value), std::rend(value)};
}
The second alternative would work if std::array could be constructed from iterators like most other containers, but they can't. One solution could be to create a helper to make sure RVO works:
using MyType = std::array<int, 26>;
namespace detail {
template<size_t... I>
constexpr MyType RevHelper(const MyType& value, std::index_sequence<I...>) {
// construct the array in reverse in-place:
return {value[sizeof...(I) - I - 1]...}; // RVO
}
} // namespace detail
constexpr MyType Reverse(const MyType& value) {
// get size() of array in a constexpr fashion:
constexpr size_t asize = std::tuple_size_v<MyType>;
// RVO:
return detail::RevHelper(value, std::make_index_sequence<asize>{});
}
Your last option is the way to go (except for the typo):
MyType Reversed2(MyType value)
{
Reverse(value);
return value;
}
[N]RVO doesn't apply to return result;, but at least it's implicitly moved, rather than copied.
You'll have either a copy + a move, or two moves, depending on the value category of the argument.
There is a trick. It is NOT pretty but it works.
Make Reversed accept not a T, but a function returning T. Call it like that:
MyType value = Reversed(SomeFunction); // note no `SomeFunction()`
Here is a full implementation of Reversed:
template <class Generator>
MyType Reversed(Generator&& g)
{
MyType t{g()};
reverse(t);
return t;
}
This produces no copies or moves. I checked.
If you feel particularly nasty, do this
#define Reversed(x) Reversed([](){return x;})
and go back to calling Reversed(SomeFunction()). Again, no copies or moves. Bonus points if you manage to squeeze it through a corporate code review.
You can use a helper method that turns your in-place operation into something that can work on Rvalues. When I tested this in GCC, it results in one move operation, but no copies. The pattern looks like this:
void Reversed(MyType & m);
MyType Reversed(MyType && m) {
Reversed(m);
return std::move(m);
}
Here is the full code I used to test whether this pattern results in copies or not:
#include <stdio.h>
#include <string.h>
#include <utility>
struct MyType {
int * contents;
MyType(int value0) {
contents = new int[42];
memset(contents, 0, sizeof(int) * 42);
contents[0] = value0;
printf("Created %p\n", this);
}
MyType(const MyType & other) {
contents = new int[42];
memcpy(contents, other.contents, sizeof(int) * 42);
printf("Copied from %p to %p\n", &other, this);
}
MyType(MyType && other) {
contents = other.contents;
other.contents = nullptr;
printf("Moved from %p to %p\n", &other, this);
}
~MyType() {
if (contents) { delete[] contents; }
}
};
void Reversed(MyType & m) {
for (int i = 0; i < 21; i++) {
std::swap(m.contents[i], m.contents[41 - i]);
}
}
MyType Reversed(MyType && m) {
Reversed(m);
return std::move(m);
}
MyType SomeFunction() {
return MyType(7);
}
int main() {
printf("In-place modification\n");
MyType x = SomeFunction();
Reversed(x);
printf("%d\n", x.contents[41]);
printf("RValue modification\n");
MyType y = Reversed(SomeFunction());
printf("%d\n", y.contents[41]);
}
I'm not sure if this lack of copies is guaranteed by the standard, but I would think so, because there are some objects that are not copyable.
Note: The original question was just about how to avoid copies, but I'm afraid the goalposts are changing and now we are trying to avoid both copies and moves. The Rvalue function I present does seem to perform one move operation. However, if we cannot eliminate the move operation, I would suggest that the OP redesign their class so that moves are cheap, or just give up on the idea of this shorter syntax.
When you write
MyType value = Reversed(SomeFunction());
I see 2 things happen: Reversed will do RVO so it directly writes to value and SomeFunction either gets coppied into the argument for Reversed or creates a temporary object and you pass a reference. No matter how you write it there will be at least 2 objects and you have to reverse from one to the other.
There is no way for the compiler to do what I would call an AVO, argument value optimization. You want the argument to the Reversed function to be stored in the return value of the function so you can do in-place operations. With that feature the compiler could do RVO-AVO-RVO and SomeFunction would create it's return value directly in the final value variable.
But you could do this I think:
MyType &&value = SomeFunctio();
reverse(value);
Looking at it another way: Say you do figure out a way for Reveresed to do in-place operations then in
MyType &&value = Reversed(SomeFunction());
the SomeFunction would create a temporary but then the compiler has to extend the lifetime of that temporary to the lifetime of value. This works in direct assignment but how is the compiler supposed to know that Reversed will just pass the temporary through?
From the answers and comments it looks like the consensus is that there is no way to achieve this in C++.
It makes sense that this is the general answer without the implementation of MyType Reversed(MyType) available, since the compiler would have no clue that the return value is the same as the argument, so it would necessarily allocate separate spaces for them.
But it looks like even with the implementation of Reversed() available, neither GCC nor Clang will optimize away the copy: https://godbolt.org/z/KW6Y3vsdf
So I think the short story is that what I was asking for isn't possible. If it's important to avoid the copy, the caller should explicitly write:
MyType value = SomeFunction();
Reverse(value);
// etc.

C++ std::vector difference between creating object then adding it vs creating it inside the vector?

Since std::vector::push_back(obj) creates a copy of the object, would it be more efficient to create it within the push_back() call than beforehand?
struct foo {
int val;
std::string str;
foo(int _val, std::string _str) :
val(_val), str(_str) {}
};
int main() {
std::vector<foo> list;
std::string str("hi");
int val = 2;
list.push_back(foo(val,str));
return 0;
}
// or
int main() {
std::vector<foo> list;
std::string str("hi");
int val = 2;
foo f(val,str);
list.push_back(f);
return 0;
}
list.push_back(foo(val,str));
asks for a foo object to be constructed, and then passed into the vector. So both approaches are similar in that regard.
However—with this approach a c++11 compiler will treat the foo object as a "temporary" value (rvalue) and will use the void vector::push_back(T&&) function instead of the void vector::push_back(const T&) one, and that's indeed to be faster in most situations. You could also get this behavior with a previously declared object with:
foo f(val,str);
list.push_back(std::move(f));
Also, note that (in c++11) you can do directly:
list.emplace_back(val, str);
It's actually somewhat involved. For starters, we should note that std::vector::push_back is overloaded on the two reference types:
void push_back( const T& value );
void push_back( T&& value );
The first overload is invoked when we pass an lvalue to push_back, because only an lvalue reference type can bind to an lvalue, like f in your second version. And in the same fashion, only an rvalue reference can bind to an rvalue like in your first version.
Does it make a difference? Only if your type benefits from move semantics. You didn't provide any copy or move operation, so the compiler is going to implicitly define them for you. And they are going to copy/move each member respectively. Because std::string (of which you have a member) actually does benefit from being moved if the string is very long, you might see better performance if you choose not to create a named object and instead pass an rvalue.
But if your type doesn't benefit from move semantics, you'll see no difference whatsoever. So on the whole, it's safe to say that you lose nothing, and can gain plenty by "creating the object at the call".
Having said all that, we mustn't forget that a vector supports another insertion method. You can forward the arguments for foo's constructor directly into the vector via a call to std::vector::emplace_back. That one will avoid any intermediate foo objects, even the temporary in the call to push_back, and will create the target foo directly at the storage the vector intends to provide for it. So emplace_back may often be the best choice.
You ‘d better use
emplace_back(foo(val,str))
if you are about creating and pushing new element to your vector. So you perform an in-place construction.
If you’ve already created your object and you are sure you will never use it alone for another instruction, then you can do
push_back(std::move(f))
In that case your f object is dangled and his content is owned by your vector.

Is there any valid reason for which a method should take a R-value reference as input?

As expressed in the title, I was wondering if there is a valid reason/example for which a given class method, excluding move constructor and move assignment operator, or free-function should take, as input parameter, a R-value reference.
Avoiding unnecessary copies when retaining values. I like to refer to this functions as "sink functions". This occurs very often when defining setters.
class A
{
private:
std::string _s;
public:
void setS(const std::string& s) { _s = s; }
void setS(std::string&& s) { _s = std::move(s); }
};
int main()
{
A a;
std::string s{"some long string ......."};
a.setS(s); // copies and retains `s`
a.setS(std::move(s)); // moves and retains `s`
}
There are two ways to model a sink argument.
The first is by taking by-value:
void foo(std::string);
the second is by rvalue reference:
void foo(std::string&&);
with the possible variant of including a const& overload to simplify work for the caller.
inline void foo(std::string const& s){
auto tmp = s;
return foo(std::move(tmp));
}
The take-sink-by-value has an extra overhead of a single std::move over taking it by && and const& (or requiring caller to manually copy a non-temporary value and move it in themselves). It doesn't require the 2nd overload.
So if that one move is worth accounting for, taking sink arguments by const& and && can save you a move. Plus, if copy is extra expensive, you can make it awkward at the call site and thus discourage it.
But that isn't the only reason. Sometimes you want to detect if something is an rvalue or lvalue, and only copy if it is an rvalue.
As an example, suppose we had a range adapter backwards. backwards takes an appropriate range (something you can for(:) over, and whose iterators can be reversed) and returns a range that iterates over it backwards.
Naively, all you have to do is get begin and end from your source range, then make reverse iterators and store them and return them from your own begin and end methods.
Sadly, this breaks:
std::vector<int> get_some_ints();
for( int x : backwards( get_some_ints() ) ) {
std::cout << x << "\n";
}
because the lifetime of the temporary returned from get_some_ints is not extended by the for(:) loop!
That for(:) expands to roughly:
{
auto&& __range_expression = backwards( get_some_ints() );
auto __it = std::begin( __range_expression );
auto __end = std::end( __range_expression );
for (; __it != __end; ++__it) {
int x = *__it;
std::cout << x << "\n";
}
}
(There are some small lies told to children above, but it is close enough for this discussion).
In particular this line:
auto&& __range_expression = backwards( get_some_ints() );
the return value of backwards is lifetime extended; but the lifetime of its arguments are not!
So if backwards takes a R const&, the vector is silently destroyed prior to the loop, and the iterators involved are invalid.
So backwards must store a copy of the vector for the above code to be valid. That is our only opportunity to make the vector last long enough!
On the other hand, in a more conventional case:
auto some_ints = get_some_ints();
for( int x : backwards( some_ints ) ) {
std::cout << x << "\n";
}
storing an extra copy of some_ints would be a horrid idea and quite unexpected.
So in this case, backwards needs to detect if its argument is an rvalue or an lvalue, and if it is an rvalue it needs to copy it and store it in the return value, and if it is an lvalue it needs to either just store iterators or a reference to it.
Sometimes you want to take ownership of something large like a std::vector but you want to avoid making a copy by accident.
By only providing an r-value reference overload a caller who wants to pass a copy has to do so explicitly:
class DataHolder {
std::vector<double> a;
std::vector<int> b;
public:
DataHolder(std::vector<double>&& a, std::vector<int>&& b) : a(a), b(b) {}
};
auto a1 = makeLotsDoubles();
auto b1 = makeLotsInts();
DataHolder holder(std::move(a1), std::move(b1)); // No copies. Good.
auto a2 = makeLotsDoubles();
auto b2 = makeLotsInts();
DataHolder holder(a2, b2) // Forgot to move, compiler error.
If instead, you had used pass-by-value then if you forget to use std::move on an lvalue then a copy is made.
It's useful to transfer an uncopyable object to the class. Some objects have no copy constructor, which means they can't be passed by value. One sees this with RAII, where creating a copy would acquire a new set of resources. Or in general, when the copy constructor and/or destructor have side effects outside the object being (de)constructed. Making a copy might not be merely inefficient, like copying a std::string, but quite impossible.
One way to pass an object like this is to pass it as a pointer. For example:
// Creates a file on construction, deletes on destruction
class File;
{
// Create files
File* logfile1 = new File("name1");
File logfile2("name2");
// Give files to logger to use
logger.add_output(logfile1); // OK
logger.add_output(&logfile2); // BAD!
}
File has no copy constructor, as a copy would create and delete the same file as the original, which makes no sense. So we pass a pointer to the file to the logger object to avoid copying. With logfile1 it works ok, assuming of course that logger deletes the File when it's done with it. But logfile2 has two big problems. One is that logger can't delete it since it wasn't allocated with new. The other is that logfile2 will be destructed, deleting the file and invalidating the pointer to it saved in logger, when logfile2 leaves scope at the end of the block.
We could give File a move constructor, which would transfer ownership of the file to the destination File and make the source File "empty". Now we can write the above code in a way that works.
{
// Create files
File* logfile1 = new File("name1");
File logfile2("name2");
// Give files to logger to use
logger.add_output(std::move(*logfile1));
logger.add_output(std::move(logfile2));
logger.add_output(File("name3"));
delete logfile1;
}
We can now create a File with new, or as a local object, or even as an unnamed pr-value. The use of std::move also makes it clear, at the call site, that ownership of the File is transferred to logger. With the pointer ownership transfer isn't clearly shown, one depends on logger.add_output() documenting the semantics and checking that documentation.

Why is string's operator+ that takes an r-value reference declared to return by value? [duplicate]

I'm trying to understand rvalue references and move semantics of C++11.
What is the difference between these examples, and which of them is going to do no vector copy?
First example
std::vector<int> return_vector(void)
{
std::vector<int> tmp {1,2,3,4,5};
return tmp;
}
std::vector<int> &&rval_ref = return_vector();
Second example
std::vector<int>&& return_vector(void)
{
std::vector<int> tmp {1,2,3,4,5};
return std::move(tmp);
}
std::vector<int> &&rval_ref = return_vector();
Third example
std::vector<int> return_vector(void)
{
std::vector<int> tmp {1,2,3,4,5};
return std::move(tmp);
}
std::vector<int> &&rval_ref = return_vector();
First example
std::vector<int> return_vector(void)
{
std::vector<int> tmp {1,2,3,4,5};
return tmp;
}
std::vector<int> &&rval_ref = return_vector();
The first example returns a temporary which is caught by rval_ref. That temporary will have its life extended beyond the rval_ref definition and you can use it as if you had caught it by value. This is very similar to the following:
const std::vector<int>& rval_ref = return_vector();
except that in my rewrite you obviously can't use rval_ref in a non-const manner.
Second example
std::vector<int>&& return_vector(void)
{
std::vector<int> tmp {1,2,3,4,5};
return std::move(tmp);
}
std::vector<int> &&rval_ref = return_vector();
In the second example you have created a run time error. rval_ref now holds a reference to the destructed tmp inside the function. With any luck, this code would immediately crash.
Third example
std::vector<int> return_vector(void)
{
std::vector<int> tmp {1,2,3,4,5};
return std::move(tmp);
}
std::vector<int> &&rval_ref = return_vector();
Your third example is roughly equivalent to your first. The std::move on tmp is unnecessary and can actually be a performance pessimization as it will inhibit return value optimization.
The best way to code what you're doing is:
Best practice
std::vector<int> return_vector(void)
{
std::vector<int> tmp {1,2,3,4,5};
return tmp;
}
std::vector<int> rval_ref = return_vector();
I.e. just as you would in C++03. tmp is implicitly treated as an rvalue in the return statement. It will either be returned via return-value-optimization (no copy, no move), or if the compiler decides it can not perform RVO, then it will use vector's move constructor to do the return. Only if RVO is not performed, and if the returned type did not have a move constructor would the copy constructor be used for the return.
None of them will copy, but the second will refer to a destroyed vector. Named rvalue references almost never exist in regular code. You write it just how you would have written a copy in C++03.
std::vector<int> return_vector()
{
std::vector<int> tmp {1,2,3,4,5};
return tmp;
}
std::vector<int> rval_ref = return_vector();
Except now, the vector is moved. The user of a class doesn't deal with it's rvalue references in the vast majority of cases.
The simple answer is you should write code for rvalue references like you would regular references code, and you should treat them the same mentally 99% of the time. This includes all the old rules about returning references (i.e. never return a reference to a local variable).
Unless you are writing a template container class that needs to take advantage of std::forward and be able to write a generic function that takes either lvalue or rvalue references, this is more or less true.
One of the big advantages to the move constructor and move assignment is that if you define them, the compiler can use them in cases were the RVO (return value optimization) and NRVO (named return value optimization) fail to be invoked. This is pretty huge for returning expensive objects like containers & strings by value efficiently from methods.
Now where things get interesting with rvalue references, is that you can also use them as arguments to normal functions. This allows you to write containers that have overloads for both const reference (const foo& other) and rvalue reference (foo&& other). Even if the argument is too unwieldy to pass with a mere constructor call it can still be done:
std::vector vec;
for(int x=0; x<10; ++x)
{
// automatically uses rvalue reference constructor if available
// because MyCheapType is an unamed temporary variable
vec.push_back(MyCheapType(0.f));
}
std::vector vec;
for(int x=0; x<10; ++x)
{
MyExpensiveType temp(1.0, 3.0);
temp.initSomeOtherFields(malloc(5000));
// old way, passed via const reference, expensive copy
vec.push_back(temp);
// new way, passed via rvalue reference, cheap move
// just don't use temp again, not difficult in a loop like this though . . .
vec.push_back(std::move(temp));
}
The STL containers have been updated to have move overloads for nearly anything (hash key and values, vector insertion, etc), and is where you will see them the most.
You can also use them to normal functions, and if you only provide an rvalue reference argument you can force the caller to create the object and let the function do the move. This is more of an example than a really good use, but in my rendering library, I have assigned a string to all the loaded resources, so that it is easier to see what each object represents in the debugger. The interface is something like this:
TextureHandle CreateTexture(int width, int height, ETextureFormat fmt, string&& friendlyName)
{
std::unique_ptr<TextureObject> tex = D3DCreateTexture(width, height, fmt);
tex->friendlyName = std::move(friendlyName);
return tex;
}
It is a form of a 'leaky abstraction' but allows me to take advantage of the fact I had to create the string already most of the time, and avoid making yet another copying of it. This isn't exactly high-performance code but is a good example of the possibilities as people get the hang of this feature. This code actually requires that the variable either be a temporary to the call, or std::move invoked:
// move from temporary
TextureHandle htex = CreateTexture(128, 128, A8R8G8B8, string("Checkerboard"));
or
// explicit move (not going to use the variable 'str' after the create call)
string str("Checkerboard");
TextureHandle htex = CreateTexture(128, 128, A8R8G8B8, std::move(str));
or
// explicitly make a copy and pass the temporary of the copy down
// since we need to use str again for some reason
string str("Checkerboard");
TextureHandle htex = CreateTexture(128, 128, A8R8G8B8, string(str));
but this won't compile!
string str("Checkerboard");
TextureHandle htex = CreateTexture(128, 128, A8R8G8B8, str);
Not an answer per se, but a guideline. Most of the time there is not much sense in declaring local T&& variable (as you did with std::vector<int>&& rval_ref). You will still have to std::move() them to use in foo(T&&) type methods. There is also the problem that was already mentioned that when you try to return such rval_ref from function you will get the standard reference-to-destroyed-temporary-fiasco.
Most of the time I would go with following pattern:
// Declarations
A a(B&&, C&&);
B b();
C c();
auto ret = a(b(), c());
You don't hold any refs to returned temporary objects, thus you avoid (inexperienced) programmer's error who wish to use a moved object.
auto bRet = b();
auto cRet = c();
auto aRet = a(std::move(b), std::move(c));
// Either these just fail (assert/exception), or you won't get
// your expected results due to their clean state.
bRet.foo();
cRet.bar();
Obviously there are (although rather rare) cases where a function truly returns a T&& which is a reference to a non-temporary object that you can move into your object.
Regarding RVO: these mechanisms generally work and compiler can nicely avoid copying, but in cases where the return path is not obvious (exceptions, if conditionals determining the named object you will return, and probably couple others) rrefs are your saviors (even if potentially more expensive).
None of those will do any extra copying. Even if RVO isn't used, the new standard says that move construction is preferred to copy when doing returns I believe.
I do believe that your second example causes undefined behavior though because you're returning a reference to a local variable.
As already mentioned in comments to the first answer, the return std::move(...); construct can make a difference in cases other than returning of local variables. Here's a runnable example that documents what happens when you return a member object with and without std::move():
#include <iostream>
#include <utility>
struct A {
A() = default;
A(const A&) { std::cout << "A copied\n"; }
A(A&&) { std::cout << "A moved\n"; }
};
class B {
A a;
public:
operator A() const & { std::cout << "B C-value: "; return a; }
operator A() & { std::cout << "B L-value: "; return a; }
operator A() && { std::cout << "B R-value: "; return a; }
};
class C {
A a;
public:
operator A() const & { std::cout << "C C-value: "; return std::move(a); }
operator A() & { std::cout << "C L-value: "; return std::move(a); }
operator A() && { std::cout << "C R-value: "; return std::move(a); }
};
int main() {
// Non-constant L-values
B b;
C c;
A{b}; // B L-value: A copied
A{c}; // C L-value: A moved
// R-values
A{B{}}; // B R-value: A copied
A{C{}}; // C R-value: A moved
// Constant L-values
const B bc;
const C cc;
A{bc}; // B C-value: A copied
A{cc}; // C C-value: A copied
return 0;
}
Presumably, return std::move(some_member); only makes sense if you actually want to move the particular class member, e.g. in a case where class C represents short-lived adapter objects with the sole purpose of creating instances of struct A.
Notice how struct A always gets copied out of class B, even when the class B object is an R-value. This is because the compiler has no way to tell that class B's instance of struct A won't be used any more. In class C, the compiler does have this information from std::move(), which is why struct A gets moved, unless the instance of class C is constant.

Does Passing STL Containers Make A Copy?

I can't remember whether passing an STL container makes a copy of the container, or just another alias. If I have a couple containers:
std::unordered_map<int,std::string> _hashStuff;
std::vector<char> _characterStuff;
And I want to pass those variables to a function, can I make the function as so:
void SomeClass::someFunction(std::vector<char> characterStuff);
Or would this make a copy of the unordered_map / vector? I'm thinking I might need to use shared_ptr.
void SomeClass::someFunction(std::shared_ptr<std::vector<char>> characterStuff);
It depends. If you are passing an lvalue in input to your function (in practice, if you are passing something that has a name, to which the address-of operator & can be applied) then the copy constructor of your class will be invoked.
void foo(vector<char> v)
{
...
}
int bar()
{
vector<char> myChars = { 'a', 'b', 'c' };
foo(myChars); // myChars gets COPIED
}
If you are passing an rvalue (roughly, something that doesn't have a name and to which the address-of operator & cannot be applied) and the class has a move constructor, then the object will be moved (which is not, beware, the same as creating an "alias", but rather transferring the guts of the object into a new skeleton, making the previous skeleton useless).
In the invocation of foo() below, the result of make_vector() is an rvalue. Therefore, the object it returns is being moved when given in input to foo() (i.e. vector's move constructor will be invoked):
void foo(vector<char> v);
{
...
}
vector<char> make_vector()
{
...
};
int bar()
{
foo(make_vector()); // myChars gets MOVED
}
Some STL classes have a move constructor but do not have a copy constructor, because they inherently are meant to be non-copiable (for instance, unique_ptr). You won't get a copy of a unique_ptr when you pass it to a function.
Even for those classes that do have a copy constructor, you can still force move semantics by using the std::move function to change your argument from an lvalue into an rvalue, but again that doesn't create an alias, it just transfers the ownership of the object to the function you are invoking. This means that you won't be able to do anything else with the original object other than reassigning to it another value or having it destroyed.
For instance:
void foo(vector<char> v)
{
...
}
vector<char> make_vector()
{
...
};
int bar()
{
vector<char> myChars = { 'a', 'b', 'c' };
foo(move(myChars)); // myChars gets MOVED
cout << myChars.size(); // ERROR! object myChars has been moved
myChars = make_vector(); // OK, you can assign another vector to myChars
}
If you find this whole subject of lvalue and rvalue references and move semantics obscure, that's very understandable. I personally found this tutorial quite helpful:
http://thbecker.net/articles/rvalue_references/section_01.html
You should be able to find some info also on http://www.isocpp.org or on YouTube (look for seminars by Scott Meyers).
Yes, it'll copy the vector because you're passing by value. Passing by value always makes a copy or move (which may be elided under certain conditions, but not in your case). If you want to refer to the same vector inside the function as outside, you can just pass it by reference instead. Change your function to:
void SomeClass::someFunction(std::vector<char>& characterStuff);
The type std::vector<char>& is a reference type, "reference to std::vector<char>". The name characterStuff will act as an alias for the object referred to by _characterStuff.
C++ is based on values: When passing object by value you get independent copies. If you don't want to get a copy, you can use a reference or a const reference, instead:
void SomeClass::someFunction(std::vector<char>& changable) { ... }
void SomeClass::otherFunction(std::vector<char> const& immutable) { ... }
When the called function shouldn't be able to change the argument but you don't want to create a copy of the object, you'd want to pass by const&. Normally, I wouldn't use something like a std::shared_ptr<T> instead. There are uses of this type by certainly not to prevent copying when calling a function.