Cannot understand why perfect forwarding is not working - c++

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.

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"
}

return const value prevent move semantics

I am a beginner in cpp so excuse me for this question.
I was reading that returning const val prevents move semantics.
therefore I dont understand why the following code is compiled and works normally. is it because only temporary object is being created? in what cases the move semantics cannot being done? thank you in advance!
#include <iostream>
using namespace std;
const string foo()
{
return string("hello");
}
int main()
{
string other = std::move(foo());
}
std::move is just a unconditional cast to rvalue. In your case the return value of std::move(foo()) was const std::string&&. And because move constructor does not take const argument, copy constructor was called instead.
struct C {
C() { std::cout << "constructor" << std::endl; }
C(const C& other) { std::cout << "copy constructor" << std::endl; }
C(C&& other) { std::cout << "move constructor" << std::endl; }
};
const C get() {
return C();
}
int main() {
C c(std::move(get()));
return 0;
}
I was reading that returning const val prevents move semantics. therefore I dont understand why the following code is compiled and works normally.
When move semantics are prevented by some mechanism, this doesn't necessarily mean that the code doesn't compile. Often, it compiles happily, but an expected move construction turns out to be a copy instead.
Example: a type has a user provided copy ctor, which disables compiler-generated move ctors. When we think we move-construct, we don't.
struct Test {
Test() = default;
Test(const Test&) {}
};
Test t1;
Test t2{std::move(t1)}; // Copies!
in what cases the move semantics cannot being done?
Coming to your example, something that is const-qualified can't be used to move-construct another object in any meaningful way. Move construction makes sense when resources can be easily transferred, but const-ness prevents that. Example: a type has compiler-generate move and copy constructors, but we can't move-construct from a const instance.
struct Test {
Test() = default;
};
const Test t1;
Test t2{std::move(t1)}; // Copies!
Besides, it doesn't make sense to move something that is returned by a function by value:
string other = std::move(foo());
When foo() returns by value, you can move-construct from it, unless the return type is const. Hence, to enable move-construction of other:
std::string foo();
string other = foo();
std::move doesn't actually move anything. It is just an "rvalue cast". You cast something to rvalue, and the move constructor / move assignment operator does the actual moving if possible. "If possible" part is the key. In your example the return value is already an rvalue, so std::move literally does nothing. You may even get warnings like "nothing is moved". That is because the move constructor of std::string takes an argument of type std::string&& not const std::string&&. Because of that, the copy constructor is called.

Did not get a compile time error after deleting copy/move constructors and assignment operators during passing object to function

I the following code I have explictly forbidden copying and moving Dummy object using delete specifier for copy and move constructors and for copy and move assignment operators:
#include <string>
#include <iostream>
struct Dummy
{
explicit Dummy(const std::string& value) : value_(value) {}
Dummy(const Dummy&) = delete;
Dummy& operator=(const Dummy&) = delete;
Dummy(Dummy&&) = delete;
Dummy& operator=(Dummy&&) = delete;
void print_this_address() const
{
std::cout << "this address: " << this << "\n";
}
std::string value_;
};
void foo(Dummy&& obj)
{
std::cout << obj.value_ << "\n";
obj.print_this_address();
}
int main()
{
Dummy obj("42");
obj.print_this_address();
foo(std::move(obj));
std::cout << obj.value_ << "\n";
return 0;
}
This code compiles and runs well and I'm getting the following output in my terminal:
this address: 0x7ffeeb6d2a20
42
this address: 0x7ffeeb6d2a20
42
Can someone explains for me what's happening in this code and why I didn't get compile error and have the same object in foo function as in main. function?
You never actually try to copy or move the object, which is why you don't get an error.
The parameter Dummy &&obj is an rvalue reference parameter, meaning it can bind to rvalues but not to lvalues. It's still a reference, just like const Dummy &obj would be (which would also work in your case).
What std::move does is not to move anything, it casts its parameter to an rvalue reference. This makes it possible to pass it to functions expecting an rvalue (for example, a move constructor). For more details have a look at the answer linked by StoryTeller.
It's not because you called std::move that your object has moved. It was just "prepared" to be moved.
As such, you prepared obj but never tried to move it somewhere else, hence the no compiler error, and as you never actually moved it (you just passed an rvalue reference to your object into foo), you get the same result, because obj never changed.

Reference binding and the copy constructor/move constructor

If I have a function like so:
int foo(std::vector<int>* integer1ArrayIn, * integer2ArrayIn) {
std::vector<int>& integer1Array = *integer1ArrayIn;
std::vector<int>& integer2Array = *integer2ArrayIn;
}
Will the reference integer1Array be calling a copy constructor/move constructor to copy over the elements of the passed in parameter?
Does binding a reference to a dereferenced pointer call the copy constructor?
In what circumstances does reference binding invoke a copy constructor?
Can someone explain what happens as this code executes in memory?
Thank you
No.
No, but it would crash badly if it was nullptr. Consider passing by reference whenever a parameter HAS to be there, and pass by pointer when a parameter MIGHT be there (but always verify for nullptr too!).
Whenever the l-value (in this case integer1Array and integer2Array) are pointers or references, it will never call copy/move constructor.
if you had std::vector integer1Array = *integer1ArrayIn it would effectively make a copy.
You can use Jonas's answer to play around with and see for yourself :)
1) No, there are no copies made. You can test it with a small program, like this.
#include <iostream>
struct foo
{
foo() { std::cout << "Constructor" << std::endl; }
foo(const foo&) { std::cout << "Copy constructor" << std::endl; }
foo& operator=(const foo&) { std::cout << "Copy assignment operator" << std::endl; }
};
int main() {
foo* A = new foo;
foo& B = *A;
delete A;
}
2) Beware of nullptrs! Otherwise all is fine.
3) Never (see answer by AlexG)
4) Not sure what you mean by "code executes in memory", since code is not executed in memory. If you mean what happens to the memory when the program is executed, then that's another story

Why move constructor is called instead of copy constructor

I'm trying to understand a move constructor,
usually a copy constructor is called when objects are copied
that what happen when I do not provide a move constructor,
but when I add a move constructor it is called instead of my copy constructor,
here is my code:
#include <iostream>
#include <vector>
using namespace std;
struct A
{
A()
{
cout << "A's constructor" << endl;
}
A(const A& rhs)
{
cout << "A's copy constructor" << endl;
}
A(A&& rhs)
{
cout << "A's move constructor" << endl;
}
};
int main() {
vector<A> v;
cout << "==> push_back A():";
v.push_back(A());
cout << "==> push_back A():" << endl;
v.push_back(A());
return 0;
}
does the compiler try to optimize my code and choose the better method ?
Basically, yes.
However, this is not about compiler optimisations as much as it is about how the language itself has been optimised.
Half of the point of move semantics is to allow efficient use of temporaries. That's why temporaries bind to rvalue refs and it's how the entire move semantics thing works. When you don't have a temporary but you wish to move something anyway, you write std::move to obtain an rvalue and trigger this same behaviour.
There is no point copying those temporaries when they are about to be destroyed anyway.
In concert with copy/move elision, this feature will result in much less redundant computing.
Note, however, that your move constructor is not terribly useful — if you ever wanted to make it actually do something (like, um, move stuff) you'd have to remove that const.
rvalue references are better candidates to bind temporaries than const lvalue references. It is not about optimizing (as in compiler optimizations), it is about following standard. The actual optimization would be to not call copy constructor at all.