I followed this tutorial to start to understand the move semantics and rvalue references in C++11.
At some point, he implements these two classes with the std::move in the move constructors explaining that
we pass the temporary to a move constructor, and it takes on new life
in the new scope. In the context where the rvalue expression was
evaluated, the temporary object really is over and done with. But in
our constructor, the object has a name; it will be alive for the
entire duration of our function. In other words, we might use the
variable other more than once in the function, and the temporary
object has a defined location that truly persists for the entire
function. It's an lvalue in the true sense of the term locator value
class MetaData
{
public:
MetaData(int size, const string& name)
: _name(name)
, _size(size)
{}
MetaData(const MetaData& other)
: _name(other._name)
, _size(other._size)
{
cout << "MetaData -- Copy Constructor" << endl;
}
MetaData(MetaData&& other)
: _name(move(other._name))
, _size(other._size)
{
cout << "MetaData -- Move Constructor" << endl;
}
~MetaData()
{
_name.clear();
}
string getName() const { return _name; }
int getSize() const { return _size; }
private:
string _name;
int _size;
};
class ArrayWrapper
{
public:
ArrayWrapper()
: _p_vals(new int[64])
, _metadata(64, "ArrayWrapper")
{}
ArrayWrapper(int n)
: _p_vals(new int[n])
, _metadata(n, "ArrayWrapper")
{}
ArrayWrapper(ArrayWrapper&& other)
: _p_vals(other._p_vals)
, _metadata(move(other._metadata))
{
cout << "ArrayWrapper -- Move Constructor" << endl;
other._p_vals = nullptr;
}
ArrayWrapper(const ArrayWrapper& other)
: _p_vals(new int[other._metadata.getSize()])
, _metadata(other._metadata)
{
cout << "ArrayWrapper -- Copy Constructor" << endl;
for (int i = 0; i < _metadata.getSize(); ++i)
_p_vals[i] = other._p_vals[i];
}
~ArrayWrapper()
{
delete[] _p_vals;
}
int* getVals() const { return _p_vals; }
MetaData getMeta() const { return _metadata; }
private:
int* _p_vals;
MetaData _metadata;
};
In the ArrayWrapper move constructor I tried to change std::move with std::forward<MetaData> and the code shows that if I call the ArrayWrapper move constructor this will call the MetaData move constructor, like the example with the std::move.
Of course if I don't use either std::move or std::forward the MetaData copy costructor will be called.
The question is, in this case, is there a difference between using std::move and std::forward? Why should I use one instead of the other?
is there a difference between using std::move and std::forward? Why should I use one instead of the other?
Yes, std::move returns an rvalue reference of its parameter, while std::forward just forwards the parameter preserving its value category.
Use move when you clearly want to convert something to an rvalue. Use forward when you don't know what you've (may be an lvalue or an rvalue) and want to perfectly forward it (preserving its l or r valueness) to something. Can I typically/always use std::forward instead of std::move? is a question you might be interested in here.
In the below snippet, bar would get exactly what the caller of foo had passed, including its value category preserved:
template <class T>
void foo(T&& t) {
bar(std::forward<T>(t));
}
Don't let T&& fool you here - t is not an rvalue reference. When it appears in a type-deducing context, T&& acquires a special meaning. When foo is instantiated, T depends on whether the argument passed is an lvalue or an rvalue. If it's an lvalue of type U, T is deduced to U&. If it's an rvalue, T is deduced to U. See this excellent article for details. You need to understand about value categories and reference collapsing to understand things better in this front.
The relevant std::forward and std::move declarations are:
template< class T >
T&& forward( typename std::remove_reference<T>::type& t );
template< class T >
typename std::remove_reference<T>::type&& move( T&& t );
For the former:
std::forward<MetaData>(other._metadata);
std::forward<MetaData> returns MetaData&&.
For the latter:
std::move(other._metadata);
//argument derived as lvalue reference due to forwarding reference
std::move<MetaData&>(other._name);
std::move<MetaData&> returns typename std::remove_reference<MetaData&>::type&&, which is MetaData&&.
So the two forms are identical for your example. However, std::move is the right choice here, as it shows our intent to unconditionally move the argument. std::forward can be used to unconditionally move, but the purpose of it is to perfect-forward its argument.
Related
As I understand rvalue being passed as an argument into function becomes lvalue,
std::forward returns rvalue if argument was passed as rvalue and lvalue if it was passed as lvalue. Here is my class:
#include <string>
#include <iostream>
struct MyClass
{
MyClass()
{
std::cout << "default";
}
MyClass(const MyClass& copy)
{
std::cout << "copy";
}
MyClass& operator= (const MyClass& right)
{
std::cout << "=";
return *this;
}
MyClass& operator= (const MyClass&& right)
{
std::cout << "mov =";
return *this;
}
MyClass(MyClass&& mov)
{
std::cout << "mov constructor";
}
};
void foo(MyClass s)
{
MyClass z = MyClass(std::forward<MyClass>(s));
}
void main()
{
auto a = MyClass();
foo(MyClass()); //z is created by move_constructor
foo(a); //z is created by move_constructor, but I think it must be created using copy constructor
}
My question is: why z variable is created using move_constructor in both cases.
I thought it must be moved in first case foo(MyClass()) and copied in 2nd case foo(a). In second case I pass lvalue as argument s, and std::forward must return lvalue, that is then is passed as lvalue reference into MyClass constructor. Where am I wrong?
I think you are sufficiently confused. The role of forward is only important when universal references come into play, and universal reference is something like T&& t but only when T is a template parameter.
For example, in void foo(X&& x); x is not a forwarding reference, it is a normal rvalue reference, and forwarding it makes no sense. Rather, you use std::move if you want to preserve it's rvalueness, otherwise it becomes an l-value:
void foo(X&& x) {
bar(x); // calls bar with an l-value x, x should be not moved from
baz(std::move(x)); // calls bar with an r-value x, x is likely moved from after this and probably unusable
}
In other words, above function foo was specifically crafted to take rvalue references as it's argument, and will not accept anything else. You, as a function writer, defined it's contract in such way.
In contrast, in a context like template <class T> void foo(T&& t) t is a forwarding reference. Due to reference collapsing rule, it could be an rvalue or an lvalue reference, depending on the valueness of the expression given to the function foo at the call site. In such case, you use
template<class T>
void foo(T&& t) {
// bar is called with value matching the one at the call site
bar(std::forward<T>(t));
}
The type of the argument that you've declared is MyClass. Whatever is the expression that initialises the argument is irrelevant in the case of your function - it does not affect the type of the argument.
MyClass is not a reference type. std::forward converts an lvalue expression of non-reference type to an rvalue. The use of std::forward in this context is equivalent to std::move.
Note that the argument itself is copy-constructed in the call foo(a).
I have a class with copy & move ctor deleted.
struct A
{
A(int a):data(a){}
~A(){ std::cout << "~A()" << this << " : " << data << std::endl; }
A(A const &obj) = delete;
A(A &&obj) = delete;
friend std::ostream & operator << ( std::ostream & out , A const & obj);
int data;
};
And I want to create a tuple with objects of this class. But the following does not compile:
auto p = std::tuple<A,A>(A{10},A{20});
On the other hand, the following does compile, but gives a surprising output.
int main() {
auto q = std::tuple<A&&,A&&>(A{100},A{200});
std::cout << "q created\n";
}
Output
~A()0x22fe10 : 100
~A()0x22fe30 : 200
q created
It means that dtor for objects is called as soon as tuple construction line ends. So, what is significance of a tuple of destroyed objects?
This is bad:
auto q = std::tuple<A&&,A&&>(A{100},A{200});
you are constructing a tuple of rvalue references to temporaries that get destroyed at the end of the expression, so you're left with dangling references.
The correct statement would be:
std::tuple<A, A> q(100, 200);
However, until quite recently, the above was not supported by the standard. In N4296, the wording around the relevant constructor for tuple is [tuple.cnstr]:
template <class... UTypes>
constexpr explicit tuple(UTypes&&... u);
Requires: sizeof...(Types) == sizeof...(UTypes). is_constructible<Ti, Ui&&>::value is true
for all i.
Effects: Initializes the elements in the tuple with the corresponding value in std::forward<UTypes>(u).
Remark: This constructor shall not participate in overload resolution unless each type in UTypes is
implicitly convertible to its corresponding type in Types.
So, this constructor was not participating in overload resolution because int is not implicitly convertible to A. This has been resolved by the adoption of Improving pair and tuple, which addressed precisely your use-case:
struct D { D(int); D(const D&) = delete; };
std::tuple<D> td(12); // Error
The new wording for this constructor is, from N4527:
Remarks: This constructor shall not participate in overload resolution unless sizeof...(Types) >= 1 and is_constructible<Ti, Ui&&>::value is true for all i. The constructor is explicit if and only
if is_convertible<Ui&&, Ti>::value is false for at least one i.
And is_constructible<A, int&&>::value is true.
To present the difference another way, here is an extremely stripped down tuple implementation:
struct D { D(int ) {} D(const D& ) = delete; };
template <typename T>
struct Tuple {
Tuple(const T& t)
: T(t)
{ }
template <typename U,
#ifdef USE_OLD_RULES
typename = std::enable_if_t<std::is_convertible<U, T>::value>
#else
typename = std::enable_if_t<std::is_constructible<T, U&&>::value>
#endif
>
Tuple(U&& u)
: t(std::forward<U>(u))
{ }
T t;
};
int main()
{
Tuple<D> t(12);
}
If USE_OLD_RULES is defined, the first constructor is the only viable constructor and hence the code will not compile since D is noncopyable. Otherwise, the second constructor is the best viable candidate and that one is well-formed.
The adoption was recent enough that neither gcc 5.2 nor clang 3.6 actually will compile this example yet. So you will either need a newer compiler than that (gcc 6.0 works) or come up with a different design.
Your problem is that you explicitly asked for a tuple of rvalue references, and a rvalue reference is not that far from a pointer.
So auto q = std::tuple<A&&,A&&>(A{100},A{200}); creates two A objects, takes (rvalue) references to them, build the tuple with the references... and destroys the temporary objects, leaving you with two dangling references
Even if it is said to be more secure than good old C and its dangling pointers, C++ still allows programmer to write wrong programs.
Anyway, the following would make sense (note usage of A& and not A&&):
int main() {
A a(100), b(100); // Ok, a and b will leave as long as main
auto q = tuple<A&, A&>(a, b); // ok, q contains references to a and b
...
return 0; // Ok, q, a and b will be destroyed
}
I have a class template with three constructors and one of them is function template.
template<class T>
class TemplateOverLoading
{
public:
TemplateOverLoading(void){};
~TemplateOverLoading(void){};
//constructor that take reference
TemplateOverLoading(std::string& qName, T& qValue )
: mName(qName),
mValue( &qValue)
{
std::cout << "Reference -> "<< *mValue <<"\n";
}
//Template constructor that takes array
template<class T, int N>
TemplateOverLoading(std::string& qName, T (&t)[N])
: mName(qName),
mValue(t)
{
std::cout << "Array ->\n";
for(int i = 0; i < N; i++)
std::cout<< mValue[i];
std::cout << std::endl;
}
//Other constructor that take pointer
TemplateOverLoading(std::string& qName, T* qValue )
: mName(qName),
mValue( qValue)
{
std::cout << "Pointer "<< *mValue <<"\n";
}
private:
T* mValue;
//T* mValueArray;
std::string& mName;
};
From my application I need to distinguish between reference type/value, pointer and array and perform specific operation. Hence I decided to have to different constructors.
I am trying to invoke the constructor in the following manner:
int init(10);
int intArray[10] = {0,1,2,3,4,5,6,7,8,9};
TemplateOverLoading<int> mInt(std::string("mInt"), init);
TemplateOverLoading<int> mIntArray( std::string("mIntArray"), intArray );
The problem is if the constructor with the pointer is defined the array constructor is never invoked. However, if I comment that one out it prints the array as it should.
Output:
(when pointer constructor is present)
Reference -> 10
Pointer 0
(when pointer constructor is not present)
Reference -> 10
Array ->
0123456789
So syntactically it is possible and it is correct deducing the the array size N.
Obviously I am confusing the compiler when the array constructor is present. So instead of letting the compiler automatically deduce I tried to specify the template parameter for the array constructor to only find out unlike the regular function, template parameters cannot be specifically specified.
I thought of introducing a dummy parameter in the array constructor to differentiate the overloading but it doesn't seem nice.
Is there any other way to resolve this? Any clue appreciated.
Make your pointer constructor parameter to T*& qValue.
TemplateOverLoading(std::string& qName, T*& qValue )
: mName(qName),
mValue( qValue)
{
std::cout << "Pointer "<< *mValue <<"\n";
}
By making it a reference to a pointer, array-to-pointer decay is prevented and the array constructor is chosen.
Also, I don't see how your code compiles, I see many errors:
Your template constructor has a parameter class T, this conflicts with the class T of the class template:
template<class T, int N>
TemplateOverLoading(std::string& qName, T (&t)[N])
This needs to be changed to something else than class T, for example class U:
template<class U, int N>
TemplateOverLoading(std::string& qName, U (&t)[N])
Your constructors also take a non-const lvalue reference, non const reference cannot bind to temporaries, which you are passing in the constructor call, i.e. std::string("mIntArray"). You need to change it to const std::string& or take it by value. Also your member std::string& mName; is a reference, you should remove the & there.
In the lecture about universal references, Scott Meyers (at approximately 40th minute) said that objects that are universal references should be converted into real type, before used. In other words, whenever there is a template function with universal reference type, std::forward should be used before operators and expressions are used, otherwise a copy of the object might be made.
My understanding of this is in the following example :
#include <iostream>
struct A
{
A() { std::cout<<"constr"<<std::endl; }
A(const A&) { std::cout<<"copy constr"<<std::endl; }
A(A&&) { std::cout<<"move constr"<<std::endl; }
A& operator=(const A&) { std::cout<<"copy assign"<<std::endl; return *this; }
A& operator=(A&&) { std::cout<<"move assign"<<std::endl; return *this; }
~A() { std::cout<<"destr"<<std::endl; }
void bar()
{
std::cout<<"bar"<<std::endl;
}
};
A getA()
{
A a;
return a;
}
template< typename T >
void callBar( T && a )
{
std::forward< T >( a ).bar();
}
int main()
{
{
std::cout<<"\n1"<<std::endl;
A a;
callBar( a );
}
{
std::cout<<"\n2"<<std::endl;
callBar( getA() );
}
}
As expected, the output is :
1
constr
bar
destr
2
constr
move constr
destr
bar
destr
The question really is why is this needed?
std::forward< T >( a ).bar();
I tried without std::forward, and it seems to work fine (the output is the same).
Similarly, why he recommends to use move inside the function with rvalue? (the answer is the same as for std::forward)
void callBar( A && a )
{
std::move(a).bar();
}
I understand that both std::move and std::forward are just casts to appropriate types, but are these casts really needed in the above example?
Bonus : how can the example be modified to produce the copy of the object that is passed to that function?
It's needed because bar() might be overloaded separately for rvalues and lvalues. That means that it might do something differently, or flat out not be allowed, depending on if you correctly described a as an lvalue or an rvalue, or just blindly treated it like an lvalue. Right now, most users don't use this functionality and don't have exposure to it because the most popular compilers don't support it - even GCC 4.8 doesn't support rvalue *this. But it is Standard.
There are two different uses for && on a parameter to a function. For an ordinary function it means that the argument is an rvalue reference; for a template function it means that it can be either an rvalue reference or an lvalue reference:
template <class T> void f(T&&); // rvalue or lvalue
void g(T&&); // rvalue only
void g(T&) // lvalue only
void h() {
C c;
f(c); // okay: calls f(T&)
f(std::move(c)); // okay: calls f(T&&)
g(c); // error: c is not an rvalue
g(std::move(c)); // okay: move turns c into an rvalue
}
Inside f and g, applying std::forward to such an argument preserves the lvalue- or rvalue-ness of the argument, so in general that's the safest way to forward an argument to another function.
void callBar( A && a )
{
std::move(a).bar();
}
In the case where you have an rvalue reference as a parameter, which can only bind to an rvalue you normally want to use move semantics to move from this this rvalue and take it's guts out.
The parameter itself is an lvalue, because it is a named thing. You can take it's address.
So in order to make it an rvalue again and be able to move from it, you apply std::move to it. If you were literally just calling a function on a passed parameter, I don't see why you'd have a parameter that is an rvalue reference.
You only want to pass an rvalue reference if you are going to move from this inside your function, which is why you then have to use std::move.
Your example here doesn't actually make much sense in that respect.
What is said in the lecture is this :
void doWork( Widget&& param )
{
ops and exprs using std::move(param)
}
SM: What this means is : if you see code that takes a rvalue reference, and you see use of that parameter without being wrapped by move, it is highly suspect.
After some thought, I realized that it is correct (as expected). Changing the callBar function in the original example to this demonstrate the point :
void reallyCallBar( A& la )
{
std::cout<<"lvalue"<<std::endl;
la.bar();
}
void reallyCallBar( A&& ra )
{
std::cout<<"rvalue"<<std::endl;
ra.bar();
}
template< typename T >
void callBar( T && a )
{
reallyCallBar( std::forward< T >( a ) );
}
If the std::forward wasn't used in callBar, then the reallyCallBar( A& ) would be used. Because a in callBar is a lvalue reference. std::forward makes it a rvalue, when the universal reference is the rvalue reference.
Next modification proves the point even further :
void reallyCallBar( A& la )
{
std::cout<<"lvalue"<<std::endl;
la.bar();
}
void reallyCallBar( A&& ra )
{
std::cout<<"rvalue"<<std::endl;
reallyCallBar( ra );
}
template< typename T >
void callBar( T && a )
{
reallyCallBar( std::forward< T >( a ) );
}
Since std::move is not used in the reallyCallBar( A&& ra ) function, it doesn't enter the endless loop. Instead it calls the version taking lvalue reference.
Therefore (as explained in the lecture) :
std::forward must be used on universal references
std::move must be used on rvalue references
Recently I have read that it makes sense when returning by value from a function to qualify the return type const for non-builtin types, e.g.:
const Result operation() {
//..do something..
return Result(..);
}
I am struggling to understand the benefits of this, once the object has been returned surely it's the callers choice to decide if the returned object should be const?
Basically, there's a slight language problem here.
std::string func() {
return "hai";
}
func().push_back('c'); // Perfectly valid, yet non-sensical
Returning const rvalues is an attempt to prevent such behaviour. However, in reality, it does way more harm than good, because now that rvalue references are here, you're just going to prevent move semantics, which sucks, and the above behaviour will probably be prevented by the judicious use of rvalue and lvalue *this overloading. Plus, you'd have to be a bit of a moron to do this anyway.
It is occasionally useful. See this example:
class I
{
public:
I(int i) : value(i) {}
void set(int i) { value = i; }
I operator+(const I& rhs) { return I(value + rhs.value); }
I& operator=(const I& rhs) { value = rhs.value; return *this; }
private:
int value;
};
int main()
{
I a(2), b(3);
(a + b) = 2; // ???
return 0;
}
Note that the value returned by operator+ would normally be considered a temporary. But it's clearly being modified. That's not exactly desired.
If you declare the return type of operator+ as const I, this will fail to compile.
There is no benefit when returning by value. It doesn't make sense.
The only difference is that it prevents people from using it as an lvalue:
class Foo
{
void bar();
};
const Foo foo();
int main()
{
foo().bar(); // Invalid
}
Last year I've discovered another surprising usecase while working on a two-way C++-to-JavaScript bindings.
It requires a combination of following conditions:
You have a copyable and movable class Base.
You have a non-copyable non-movable class Derived deriving from Base.
You really, really do not want an instance of Base inside Derived to be movable as well.
You, however, really want slicing to work for whatever reason.
All classes are actually templates and you want to use template type deduction, so you cannot really use Derived::operator const Base&() or similar tricks instead of public inheritance.
#include <cassert>
#include <iostream>
#include <string>
#include <utility>
// Simple class which can be copied and moved.
template<typename T>
struct Base {
std::string data;
};
template<typename T>
struct Derived : Base<T> {
// Complex class which derives from Base<T> so that type deduction works
// in function calls below. This class also wants to be non-copyable
// and non-movable, so we disable copy and move.
Derived() : Base<T>{"Hello World"} {}
~Derived() {
// As no move is permitted, `data` should be left untouched, right?
assert(this->data == "Hello World");
}
Derived(const Derived&) = delete;
Derived(Derived&&) = delete;
Derived& operator=(const Derived&) = delete;
Derived& operator=(Derived&&) = delete;
};
// assertion fails when the `const` below is commented, wow!
/*const*/ auto create_derived() { return Derived<int>{}; }
// Next two functions hold reference to Base<T>/Derived<T>, so there
// are definitely no copies or moves when they get `create_derived()`
// as a parameter. Temporary materializations only.
template<typename T>
void good_use_1(const Base<T> &) { std::cout << "good_use_1 runs" << std::endl; }
template<typename T>
void good_use_2(const Derived<T> &) { std::cout << "good_use_2 runs" << std::endl; }
// This function actually takes ownership of its argument. If the argument
// was a temporary Derived<T>(), move-slicing happens: Base<T>(Base<T>&&) is invoked,
// modifying Derived<T>::data.
template<typename T>
void oops_use(Base<T>) { std::cout << "bad_use runs" << std::endl; }
int main() {
good_use_1(create_derived());
good_use_2(create_derived());
oops_use(create_derived());
}
The fact that I did not specify the type argument for oops_use<> means that the compiler should be able to deduce it from argument's type, hence the requirement that Base<T> is actually a real base of Derived<T>.
An implicit conversion should happen when calling oops_use(Base<T>). For that, create_derived()'s result is materialized into a temporary Derived<T> value, which is then moved into oops_use's argument by Base<T>(Base<T>&&) move constructor. Hence, the materialized temporary is now moved-from, and the assertion fails.
We cannot delete that move constructor, because it will make Base<T> non-movable. And we cannot really prevent Base<T>&& from binding to Derived<T>&& (unless we explicitly delete Base<T>(Derived<T>&&), which should be done for all derived classes).
So, the only resolution without Base modification here is to make create_derived() return const Derived<T>, so that oops_use's argument's constructor cannot move from the materialized temporary.
I like this example because not only it compiles both with and without const without any undefined behaviour, it behaves differently with and without const, and the correct behavior actually happens with const only.