C++ move constructor not called [duplicate] - c++

This question already has answers here:
Why do I have to call move on an rvalue reference?
(2 answers)
Rvalue Reference is Treated as an Lvalue?
(4 answers)
Closed 5 years ago.
In the following (borrowed) example, in my environment the move constructor is never called:
#include <iostream>
class MyClass {
public:
MyClass()
{
std::cout << "default constructor\n";
}
MyClass(MyClass& a)
{
std::cout << "copy constructor\n";
}
MyClass(MyClass&& b)
{
std::cout << "move constructor\n";
}
};
void test(MyClass&& temp)
{
MyClass a(MyClass{}); // calls MOVE constructor as expected
MyClass b(temp); // calls COPY constructor...
}
int main()
{
test(MyClass{});
return 0;
}
My output is:
default constructor
default constructor
copy constructor
I use XCode version 9.1, shouldnt the move constructor be called on rvalue references? What am I missing here?
John.

What am I missing here?
The point is that everything that has a name is lvalue.
It means that named rvalue reference itself is lvalue and temp from:
void test(MyClass&& temp)
is lvalue as well. So move constructor is not called.
If you want a move constructor to be called, use std::move:
void test(MyClass&& temp)
{
// ...
MyClass b(std::move(temp)); // use std::move here
}
By the way,
MyClass(MyClass& a)
{
std::cout << "copy constructor\n";
}
is not a copy constructor because copy constructor has a form of:
MyClass(const MyClass& a) { ... }

Related

Why this code is not calling move constructor?

I have this simple piece of code in C++17 and I was expecting that the move constructor was called (or the copy constructor, if I was doing something wrong), while it is just calling the normal constructor and I cannot why is doing this optimization.
I am compiling with -O0 option.
#include <iostream>
using namespace std;
struct Foo {
int m_x;
Foo(int x) : m_x(x) { cout << "Ctor" << endl; }
Foo(const Foo &other) : m_x(other.m_x) { cout << "Copy ctor" << endl; }
Foo(Foo &&other) : m_x(other.m_x) {
other.m_x = 0;
cout << "Move ctor" << endl;
}
};
void drop(Foo &&foo) {}
int main() { drop(Foo(5)); }
I cannot why is doing this optimization.
This is not due to any optimization in C++17. Instead this is due to the fact that you're passing an int when you wrote Foo(5). And since you've provided a converting constructor Foo::Foo(int), it will be used to create a Foo object which will then be bound to the rvalue reference parameter of drop.
Note that in C++17, even if we were to make the parameter of drop to be of type Foo instead of Foo&&, then also there will be no call to the move constructor because of mandatory copy elison.
C++11
On the other hand, if you were using C++11 and using the flag -fno-elide-constructors and parameter to drop was of type Foo instead of Foo&& then you could see that a call would be made to the move ctor.
//--------vvv-----------> parameter is of type Foo instead of Foo&&
void drop(Foo foo) {
std::cout<<"drop called"<<std::endl;
}
int main() {
drop(Foo(5)); //in c++11 with -fno-elide-constructors the move ctor will be called
}
The output of the above modified version in C++11 with -fno-elide-constructors is:
Ctor
Move ctor
drop called
Demo
In function main you create a temporary Foo object from integer 5 but you don't move (nor copy) from it anywhere. To actually call your move (or copy) constructor, you have to move- (or copy-) construct another object from your temporary Foo.
E.g., to call Foo's move constructor:
void drop(Foo &&foo) {
// Move-construct tmp from foo.
Foo tmp { std::move(foo) };
}

Why is move-constructor not called? [duplicate]

This question already has answers here:
Why are rvalues references variables not rvalue?
(3 answers)
Closed 1 year ago.
I have the following piece of code:
#include <iostream>
struct T {
int a;
T() = default;
T(T& other) {
std::cout << "copy &\n";
}
T(T&& other) {
std::cout << "move &&\n";
}
};
void foo(T&& x) {
T y(x); // why is copy ctor called??????
}
int main() {
T x;
foo(std::move(x));
return 0;
}
I don't understand why copy constructor is preferred over move constructor even though foo() accepts rvalue-reference.
x is an lvalue itself, even its type is rvalue-reference. Value category and type are two independent properties.
Even if the variable's type is rvalue reference, the expression consisting of its name is an lvalue expression;
You need to use std::move to convert it to rvalue, just same as using std::move on x in main().
void foo(T&& x)
{
T y(std::move(x));
}

Given a rvalue, why move ctor is a better match than const copy ctor? [duplicate]

This question already has answers here:
What is copy/move constructor choosing rule in C++? When does move-to-copy fallback happen?
(2 answers)
Closed 4 years ago.
Sample code, C++11, -fno-elide-constructors.
#include <iostream>
#include <string>
using namespace std;
class ClassA
{
int a, b;
public:
ClassA() = default;
ClassA(const ClassA &obj)
{
cout << "copy constructor called" << endl;
}
ClassA(ClassA &&obj) {
cout << "move ctor called" << endl;
}
};
ClassA bar(ClassA &str)
{
return str; //call copy ctor
}
int main()
{
ClassA str;
ClassA foo = bar(str); //call move ctor
return 0;
}
https://wandbox.org/permlink/DyALfRETs2LfWSjc
Why this assignment ClassA foo = bar(str); call move ctor instead of copy ctor? Since both const lvalue reference and rvalue reference can accept rvalue.
const lvalue reference can bind to everything, so if the compiler would favor this over the rvalue reference the move constructor would not be called ever if a copy constructor is provided, and that would defeat the purpose of having both.
The rvalue reference accepting function is a more specialized version of the more generic const lvalue reference accepting one, and the compiler always chooses the most specialized version.

C++ move constructor not called for rvalue reference [duplicate]

This question already has answers here:
On how to recognize Rvalue or Lvalue reference and if-it-has-a-name rule
(3 answers)
Closed 6 years ago.
class MyClass {
public:
MyClass()
{
std::cout << "default constructor\n";
}
MyClass(MyClass& a)
{
std::cout << "copy constructor\n";
}
MyClass(MyClass&& b)
{
std::cout << "move constructor\n";
}
};
void test(MyClass&& temp)
{
MyClass a(MyClass{}); // calls MOVE constructor as expected
MyClass b(temp); // calls COPY constructor... not expected...?
}
int main()
{
test(MyClass{});
return 0;
}
For the above code, I expected both object creations in test() to call move constructor because b is a r-value reference type (MyClass&&).
However, passing b to the MyClasss constructor does not call move constructor as expected, but calls copy constructor instead.
Why does second case calls copy constructor even if the passed argument is of type MyClass&& (r-value reference)???
I am using gcc 5.2.1. To reproduce my results, you must pass -fno-elide-constructors option to gcc to disable copy elision optimization.
void test(MyClass&& temp)
{
if (std::is_rvalue_reference<decltype(temp)>::value)
std::cout << "temp is rvalue reference!!\n";
else
std::cout << "temp is NOT rvalue!!\n";
}
Above code prints out "temp is rvalue reference" even if temp is named.
temp's type is rvalue reference type.
void test(MyClass&& temp)
{
MyClass a(MyClass{}); // calls MOVE constructor as expected
MyClass b(temp); // calls COPY constructor... not expected...?
}
That is because, temp (since it has a name,) is an lvalue reference to an rvalue. To treat as an rvalue at any point, call on std::move
void test(MyClass&& temp)
{
MyClass a(MyClass{}); // calls MOVE constructor as expected
MyClass b(std::move(temp)); // calls MOVE constructor... :-)
}

C++: why constructor "A(A a) {}" is illegal? [duplicate]

This question already has answers here:
Why should the copy constructor accept its parameter by reference in C++?
(9 answers)
Closed 8 years ago.
I met a quiz saying that the code below is ill-formed because "It is illegal to have a constructor whose first and only non-default argument is a value parameter for the class type."
I couldn't understand that. Why things like A(A a) : val (a.val) {} is ruled as illegal? why such a line in the standard? Is it because this will lead to ambiguity with copy constructor?
#include <iostream>
struct A
{
A() : val() {}
A(int v) : val(v) {}
A(A a) : val(a.val) {}
int val;
};
int main(int argc, char** argv)
{
A a1(5);
A a2(a1);
std::cout << a1.val + a2.val << std::endl;
return 0;
}
A(A a) : val(a.val) {} will cause an infinite recursion because constructor arguments are being copied by value (invoking copy constructor and again the copy constructor and ...)
A copy constructor is called when an object is passed by value. Copy constructor itself is a function. So if we pass argument by value in a copy constructor, a call to copy constructor would be made to call copy constructor which becomes a non-terminating chain of calls. Therefore compiler doesn’t allow parameters to be pass by value
Its already discussed on this SO post
Why should the copy constructor accept its parameter by reference in C++?
Everything changes with const:
#include <iostream>
struct A
{
A () : _a(0) {}
A (int a) : _a(a) {}
A (const A& a) : _a(a._a) {}
int _a;
};
int main()
{
A a(5);
A b(10);
A c(a);
std::cout << a._a + b._a + c._a << std::endl; // 20
return 0;
}