Move constructor not called - c++

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.

Related

construction and destruction of parameterized constructor argument?

Here, i am getting different out on different compiler, why is that ?
On msvc compiler, there i'm getting extra destructor statement ?
Why i'm getting this behaviour ?
Am i missing something ?
i had looked many question on stackoverflow, but i can't find anything related to my problem ?
i also tried to look for duplicate, but didn't find one.
class A {
public:
A()
{
std::cout << "A::constructor" << "\n";
}
~A()
{
std::cout << "A::Destructor" << "\n";
}
int x = 0;
int y = 0;
};
class B {
public:
A member_var_1;
int member_var_2;
B()
{
std::cout << "B::constructor" << '\n';
}
B(A a, int b)
{
member_var_1 = a;
member_var_2 = b;
std::cout << "B(A, int)::constructor " << '\n';
}
~B()
{
std::cout << "B::destructor" << '\n';
}
};
int main()
{
B v1 {A(), 5};
}
GCC output:
A::consturctor // parameterized constructor first argument constructor
A::consturctor // construction of B's class member (member_var_1)
B(A, int)::consturcotr // B class parameterized constructor
A::Destructor // Destruction of argument of parameterized constructor
B::destructor // object goes out of scope, so B destructor called
A::Destructor // B's Destructor called member's destructor
MSVC output:
A::consturctor
A::consturctor
B(A, int)::consturcotr
A::Destructor
A::Destructor // what is it destroying? if i define a "class A" copy constructor, then i don't get this output.
B::destructor
A::Destructor
Since you're using C++17 and there is mandatory copy elision from C++17(&onwards), the extra destructor call must not be there.
A msvc bug has been reported as:
MSVC produces extra destructor call even with mandatory copy elision in C++17
Note that if you were to use C++11 or C++14, then it was possible to get an extra destructor call because prior to c++17 there was no mandatory copy elision and the parameter a could've been created using the copy/move constructor which means that you'll get the fourth destructor call as expected. You can confirm this by using the -fno-elide-constructors flag with other compilers. See Demo that has a contrived example of this.
B v1 {A(), 5};
In MSCV compiler, first, the construction of temporary A() is happening then it is elided to to "a" argument of parameterized constructor. that's why the extra destruction is happening for this temporary but it shouldn't be here because it is done implicitly.
So it is a bug in MSCV.

Is it best practice to use a initializer_list in assignment

I have read (Bjarne Stroustrup, The C++ Programming Language, 6.3.5) about using initializer_list when initializing a variable, so that you don't have a narrowing conversion. Bjarne recommends only using direct-list-initialization :
X a1 {v};
X a2 = {v};
X a3 = v;
X a4(v);
Of these, only the first can be used in every context, and I strongly
recommend its use. It is clearer and less error-prone than the
alternatives.
Why does Bjarne only recommend the first one?
Why isn't it recommended to do initializer_list in assignment (rather than initialization)? Or is it just implied that you should do that?
a1 = {v};
Here is an example of what I am asking about? Why is initializer_list not recommended for assignment (from what I can tell) but it is recommended for initialization? It seems like it is beneficial by reducing potential narrowing conversions on accident.
char c;
int toobig = 256;
c = 256; //no error, narrowing occurs
c = { toobig }; //narrowing conversion, error
Initializer lists are usually recommended and overcome a syntactic trap called 'The Most Vexxing Parse'.
std::vector<int> v();
Inside a function this looks like variable declaration but it's a declaration of a function v taking no arguments returning a std::vector<int>.
OK so std::vector<int> v; fixes that one but in a template a parameter may be a built in type where int x; leaves x uninitialized but int x{}; (value) initializes it to zero.
In modern C++ with copy elision and a couple of syntatic rules, there aren't that many ways to accidentally create temporary copies in a variable declaration.
But initializer-lists do clear up a couple of anomalies and are to be recommended.
Overloading in C++ is quite keen and there remain reasons to sometimes use () to call the appropriate constructor.
For example std::vector<T> can take a initializer-list of values and create an array containing that list. Great.
It can also take count and value arguments and create an array of count copies of `value'. Also great.
But if the size type is compatible with the value-type (T) you can still get a surprise!
#include <iostream>
#include <vector>
template<typename T>
void dump_vector(const std::string& tag,const std::vector<T>& vec);
int main() {
std::vector<int> v1(5,20);
std::vector<int> v2{5,20};
std::vector<std::string> v3(5,"Hi!");
std::vector<std::string> v4{5,"Hi!"};
dump_vector("v1",v1);
dump_vector("v2",v2);
dump_vector("v3",v3);
dump_vector("v4",v4);
return 0;
}
template<typename T>
void dump_vector(const std::string& tag,const std::vector<T>& vec){
std::cout<< tag << "={ ";
auto begin=vec.begin();
auto end=vec.end();
for(auto it{begin};it!=end;++it){
if(it!=begin){
std::cout<<", ";
}
std::cout<<*it;
}
std::cout << " }\n";
}
Expected output:
v1={ 20, 20, 20, 20, 20 }
v2={ 5, 20 }
v3={ Hi!, Hi!, Hi!, Hi!, Hi! }
v4={ Hi!, Hi!, Hi!, Hi!, Hi! }
The versions with () and {} did different things for std::vector<int> but landed on the same constructor for std::vector<std::string>.
This isn't a new or unique problem. C++ uses types heavily in selecting an overload and when there's a bunch of candidates different template instantiations might make an unexpected choice!
I'd say initializer-list is now preferred. But when a constructor that itself takes in initializer list exists, you may need to be explict if you don't want to hit it.
Also worth a read http://read:%20https://herbsutter.com/2013/05/09/gotw-1-solution/
Take this as example
#include <iostream>
struct foo
{
explicit foo(int)
{
std::cout << "[+] c'tor called\n";
}
foo(const foo&)
{
std::cout << "[+] copy c'tor called\n";
}
};
int main()
{
std::cout << "\ncreating object a\n";
foo a = foo{1};
std::cout << "\n\ncreating object b\n";
foo b{1};
}
Compiling with g++ main.cpp --std=c++11 -fno-elide-constructors
Output:
creating object a
[+] c'tor called
[+] copy c'tor called
creating object b
[+] c'tor called
In the first a temporary is created and then a is created by calling the copy constructor.
Whereas in second example the object is directly created.
There are few cases where you have to use () syntax instead of {}.
Refer to Scott Meyers-Effective Modern C++ (item 7)`

Is there any difference between copy constructor/copy assignment and normal function call optimization in compiling?

I met one interesting compiling error when testing one small example:
#include <iostream>
using namespace std;
class A
{
public:
A() { cout <<"A created." <<endl; }
A(A& a) { cout <<"A created by copy constructor." <<endl; }
~A() { cout <<"A destoryed." <<endl; }
};
A CreateObject()
{
A obj;
return obj;
}
int main()
{
A a;
A b;
b= CreateObject();
return 0;
}
it's simple and may not have any issues at all. however, it prompted in compiling:
copy_constructor.cpp: In function ‘int main()’:
copy_constructor.cpp:23: error: no matching function for call to ‘A::A(A)’
copy_constructor.cpp:9: note: candidates are: A::A(A&)
it seems that the program tried to call copy constructor when compiling "b= CreateObject();" but there is no matching copy constructor. this should not happen because it just one assignment statement, is there any difference between constructor and normal function in compiling optimization ?
A(A& a) { cout <<"A created by copy constructor." <<endl; }
...
b = CreateObject();
This is invalid according to C++03 standard.
In C++03, b = CreateObject() may actually expand to b = A(CreateObject());. This has only been "fixed" in later versions of C++, where the creation of the temporary copy is now prohibited.
CreateObject() returns a r-hand value which can only be consumed by copy constructor with a A(const A& a) signature. Without the const modifier, it's only applicable to l-hand values.
E.g. b = a would still have been valid with that signature and the expansion, because you would be allowed to modify a inside the constructor.
This is still replicable setting clang++ to C++98 standard: http://coliru.stacked-crooked.com/a/50c25c469420ab0f
Older versions of Visual-C++ exhibit the precise error shown by the OP.
g++ fails to validate this correctly, even when explictly specifying C++98.
See also https://stackoverflow.com/a/13898867/2879325
The code you've posted compiles just fine. You should however change your copy constructor from A(A&) to A(const A&).

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()

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

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