Is this code legal? (C++0x move semantics) - c++

I'm curious as to whether this code is legal in C++0x. Specifically, will the object declared in the function move_it() be properly moved to the object declared in main()?
#include <iostream>
#include <string>
#include <tr1/memory>
using namespace std;
class x
{
public:
x() { cout << "create " << this << endl; }
~x() { cout << "destroy " << this << endl; }
};
x&& move_it()
{
x r;
return move(r);
}
int main()
{
x n = move_it();
return 0;
}

No, it is returning a reference to a local object, just like with an lvalue reference.
Just return it by value and let x's assumed move constructor pick up the rvalue. When you return by value, the returned object is an rvalue.
If you are lucky, the NRVO optimization will kick in (just like before) and elide the copying anyway.

You are returning a dangling rvalue reference from move_it, which invokes undefined behavior when you access it in main.
If you want to move the object, change the return type to x and get rid of the move:
x move_it()
{
x r;
return r;
}
(Automatic variables are implicitly treated as rvalues when returned from a function.)

As a regular user, anyone not implementing a template library, the only use for r-value references you should make is in implementing move constructors and move assignment.
Check out this video http://channel9.msdn.com/Shows/Going+Deep/C9-Lectures-Stephan-T-Lavavej-Standard-Template-Library-STL-9-of-n

Related

Is there a way for a member function to know if the object is an rvalue or lvalue?

My usecase is I have a class X which has a member function that returns a modified copy of X. Some of these member functions might be stacked like this
X X_before{init};
X X_after = X_before.op_1().op_2().op_3();
In the above code op_1 would create a copy. Now what I am thinking is that there's really no reason why op_2 and op_3 should also need to create a new copy, since X_before.op_1() is now an rvalue. Is there a way that I could achieve this in current C++? I am using C++14, but would also be interested to know if this is possible in later versions.
Since C++11 we have ref-qualified member functions, with that overload resolution could select the appropriate overloading based on the object to be called on is lvalue or rvalue.
#include <iostream>
struct S {
void f() & { std::cout << "lvalue\n"; }
void f() &&{ std::cout << "rvalue\n"; }
};
int main(){
S s;
s.f(); // prints "lvalue"
std::move(s).f(); // prints "rvalue"
S().f(); // prints "rvalue"
}

Cannot understand why perfect forwarding is not working

I am trying to understand how perfect forwarding works but I cannot understand why the copy constructor is called in the code below
#include <utility>
#include <iostream>
using std::cout;
using std::endl;
class Something {
public:
Something() = default;
Something(__attribute__((unused)) const Something& other) {
cout << "Copy constructor called" << endl;
}
Something(__attribute__((unused)) Something&& other) {
cout << "Move constructor called" << endl;
}
void print() {
cout << "Something::print() called" << endl;
}
};
void function_1(Something&& one) {
cout << "version two called" << endl;
Something inner{one};
inner.print();
}
void function_1(const Something& one) {
Something inner(one);
inner.print();
}
template <typename... T>
void test_function(T&&... ts) {
function_1(std::forward<T>(ts)...);
}
int main() {
const Something some1 {Something()};
test_function(some1);
test_function(Something());
return 0;
}
This produces the following output
Copy constructor called
Something::print() called
version two called
Copy constructor called
Something::print() called
Changing the code to include std::move in the rvalue reference works but I did not expect to need it. When a reference is an rvalue reference the correct constructor should be called automatically right? The correct reference is resolved but the wrong constructor is being called. Any help would be greatly appreciated!
An rvalue reference binds to rvalues. It is not itself an rvalue, for it has a name.
But anything with a name at point of use is an lvalue by default, even rvalue references. Your code could use Something&& one three times, and if the first use implicitly moves you would be screwed.
Instead, it is an lvalue at point of use (by default), and it binds to an rvalue.
When you want to signal you no longer require its state to persist, std::move it.
Perfect forwarding can be used to write both of your function_1s by putting a std::forward<Blah>(blah) at the point where you'd want to move from blah if it was an rvalue reference.
Now the above is full of lies, for there are xvalues prvalues lvalues etc -- the standard is more complex. The use of a variable in return statements can turn a named value into an rvalue, for example. But the basic rule of thumb is worth knowing: it has a name, it is an lvalue (except if explicitly casted, or expiring).
This code will call the copy ctor, not the move ctor.
void function_1(Something&& one) {
cout << "version two called" << endl;
Something inner{one};
inner.print();
}
This code calls the move ctor.
void function_1(Something&& one) {
cout << "version two called" << endl;
Something inner{std::move(one)};
inner.print();
}
The expression one is technically an l-value. It refers to an rvalue-reference. But to actually get the rvalue-reference you have to use std::move. Generally anything that has a name is an l-value. Unnamed temporaries, like your Something() expression in main():
test_function(Something());
can be rvalue's and can invoke a move without using std::move.

Does returning a temporary object create a temporary object in C++?

Consider the following code in C++:
struct A {A(int);};
A foo() {return static_cast<A>(0);}
A x = foo();
Here static_cast<A>(0) creates a temporary object by the standard [5.2.9-4], which is a prvalue. The standard [12.2-1] says
Temporaries of class type are created in various contexts: binding a reference to a prvalue (8.5.3), returning a prvalue (6.6.3), a conversion that creates a prvalue (4.1, 5.2.9, 5.2.11, 5.4), throwing an exception (15.1), entering a handler (15.3), and in some initializations (8.5).
So does the return statement will creates a temporary object again?
By the way, can anyone please tell me whether the standard guarantees an implicit type conversion will create an temporary object?
(ยง4/6) mentions that
The effect of any implicit conversion is the same as performing the corresponding declaration and initialization and then using the temporary variable as the result of the conversion.
So yes, unless optimized, a temporary should be created, but I'm sure all modern compilers will perform a copy elision in your case. This particular optimization is called return value optimization (RVO). You can easilly test it by having constructors with side effects:
struct A {
A(int){
std::cout << "ctor";
}
A(const A & other)
{
std::cout << "copy ctor";
}
A(A&&other)
{
std::cout << "move ctor";
}
};
The temporary object will (most likely) be optimized away through Return-Value-Optimization (RVO) .
Example:
#include <iostream>
struct A
{
A(int)
{
std::cout<< "A" << std::endl;
}
A(const A&)
{
std::cout << "A&" << std::endl;
}
A(A&&)
{
std::cout << "A&&" << std::endl;
}
};
A foo() {return static_cast<A>(0);}
int main()
{
A x = foo();
return 0;
}
output: live example
A
output with RVO disabled: live example
A
A&&
A&&
Short answer: No there will be only one creation of A in your code.
To achieve this, the compiler uses the (Named) Return value optimization that eliminates unnecessary object creation/copy upon returns. The more general case, Copy elision, that eliminates unnecessary copying of objects, will be use in plenty of related case.
You can play with GCC option -fno-elide-constructors to see the differences.
The actual result in this particular case will depend on a particular compiler and optimization levels. In fact, a decent modern compiler with a good optimization level can completely remove any temporary object. Consider this:
#include <iostream>
using namespace std;
struct A {
A(int) { cout << __PRETTY_FUNCTION__ << endl; }
~A() { cout << __PRETTY_FUNCTION__ << endl; }
};
inline
A foo() {
return static_cast<A>(0);
};
int main(void) {
A a = foo();
cout << "hello world!" << endl;
}
gcc-5.1.1 with -O4 builds an executable which outputs literally this:
A::A(int)
hello world!
A::~A()

Move constructor not called

After trying to write an example regarding move constructors, I ran into the following code:
#include <utility>
#include <iostream>
using namespace std;
class Data
{
public:
Data()
: x (3)
{
cout << "Data()" << endl;
}
Data(Data&&)
: x(4)
{
cout << "Data(&&)" << endl;
}
int x;
};
int main()
{
Data a;
Data b (std::move(a));
cout << b.x << endl;
return 0;
}
Why is the move constructor not called here?
The program prints:
Data()
3
What I'm finding even weirder is that by adding a copy constructor, suddenly, it does call the move constructor...
Data(const Data&)
: x(2)
{
cout << "Data(copy)" << endl;
}
And now it will print
Data(&&)
4
P.S I'm using gcc 4.4.5
Well, your code works properly for me. See this sample.
Output:
Data()
Data(&&)
4
As standard says:
The move constructor is called whenever an object is initialized from
xvalue of the same type, which includes
initialization, T a = std::move(b); or T a(std::move(b));, where b is of type T
function argument passing: f(std::move(a));, where a is of type T and f is void f(T t)
function return: return a; inside a function such as T f(), where a is of type T which has a move constructor.
And
std::move obtains an rvalue reference to its argument and converts it to an xvalue.
I see no reason for behavior you describe. Perhaps there is something wrong with your compiler?
EDIT
It seems, that it is indeed the fault of the compiler. Definition of move functions was described in proposal N3053 ("Defining Move Special Member Functions"). As we can see in table on this page:
Your code is well-formed and should call the move constructor. However, gcc 4.4, does not support defining move functions as stated here.
You do want to consider to update your compiler.

C++ const lvalue references

Assuming I have:
class A which is non-copyable
class B which has as a member, const A& a (and takes an A in its constructer and sets it in its initialization list)
a function A GenerateA();
Does this mean that it should be valid to do:
B(GenerateA())
?
i.e, does the const ref mean that no copy of the A that generateA() returns is done? And does that mean that the scope of the returned temporary is extended for as long as B exists?
EDIT: Addon question from the comments:
Is it acceptable to return a A& from GenerateA() to a local A, if the lvalue is a const A&?
Thanks!
If A is non-copyable, then the function A GenerateA() is invalid since returning by value requires creating a copy.
If the function returns a reference instead (i.e. A &GenerateA()) and the reference is to a locally created A object, it becomes invalid as soon as the function exits. C++ doesn't have any form of garbage collection, so there is no way to "extend" the lifetime of an object as long as it is in use.
As it has already been stated by others, A GenerateA() cannot compile if A is not copyable.
Regarding the const ref : no, the lifetime of the temporary will not be extended to the lifetime of B. The standard [12.2.5] states :
A temporary bound to a reference member in a constructor's ctor-initializer (12.6.2) persists until the constructor exits. [...] A temporary bound to the returned value in a function return statement (6.6.3) persists until the function exits.
So yes, extension of the lifetime of a temporary exists in some contexts (and is sometime truly useful : see this article), but not in the one you presented.
Regarding your last question, it's not legal to return a reference to a local variable from GenerateA() (and binding the result to a const reference won't be of any help).
Yes and No.
Yes, the const reference will bind to the temporary variable. No, const references which are class members do not extend lifetime the way const references with automatic duration do.
Here's an example:
#include <iostream>
using namespace std;
int& GenX(bool reset)
{
static int* x = new int;
*x = 100;
if (reset)
{
delete x;
x = new int;
*x = 200;
}
return *x;
}
class YStore
{
public:
YStore(int& x);
int& getX() { return my_x; }
private:
int& my_x;
};
YStore::YStore(int& x)
: my_x(x)
{
}
int main()
{
YStore Y(GenX(false));
cout << "X: " << Y.getX() << endl;
GenX(true); // side-effect in Y
cout << "X: " << Y.getX() << endl;
return 0;
}
Output:
X: 100
X: 200