Move constructors not getting called

ey guys,to my surprise it seems like the move constructors are not being called when I set an object = to an rvalue object,

this took me by surprise,the object seems to have been moved by the move constructor was skipped instead the normal constructor with two arguments has run instead,what is going on here?

thanks


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
#include <iostream>
#include <stdio.h>
#include <algorithm>

using namespace std;

class Object{

public:


  int number;
  string* name;
  string nme;

  Object(){
     cout << "normal cons" << endl;
  }

  Object(int nm,string n)
    :number(nm),name(new string(n)),nme(n)
  {cout << "normal with params" << endl;}

  Object(const Object& other){

     cout << "copy cons" << endl;
     number = other.number;
     nme = other.nme;
     name = new string(nme);
  }
  Object& operator=(Object cp){

      cout << "op = " << endl;
      swap(*this,cp);
  }

  Object(Object&& other) 
    {
        cout << "move cons" << endl;

        number = other.number;
        nme = other.nme;
        name = other.name;
        other.name = nullptr;
    }

  void swap(Object& a,Object& b){

      using std::swap;
      swap(a.number,b.number);
      swap(a.nme,b.nme);
      swap(a.name,b.name);

  }
};


int main()
{
   

  // Object a(20,"adam");
  // Object b(a);
   // Object c(40,"Bill");
    Object d = Object(10,"Steve");
//
 //   c = a;
//
//   cout << a.name->c_str() << endl;
//   cout << b.name->c_str() << endl;
//   cout << c.name->c_str() << endl;
//   cout << d.name->c_str() << endl;


}
Last edited on
See: http://en.cppreference.com/w/cpp/language/copy_elision

It has the example:
1
2
3
T f() { return T{}; }
T x = f();         // only one call to default constructor of T, to initialize x
T* p = new T(f()); // only one call to default constructor of T, to initialize *p 


It also applies to your initialization of d.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <iostream>
#include <string>

class Object
{
public:
        Object() { std::cout << "default constructor" << std::endl; }
        ~Object() { std::cout << "destructor" << std::endl; }
        Object(int, std::string) { std::cout << "param constructor" << std::endl; }
        Object(const Object&) { std::cout << "copy constructor" << std::endl; }
        Object& operator=(const Object&) { std::cout << "assign" << std::endl; return *this; }
        Object(Object&&) { std::cout << "move constructor" << std::endl; }
        Object& operator=(Object&&) { std::cout << "move assign" << std::endl; return *this; }
};

int main()
{
        Object d = Object(10, "Steve");
}

Last edited on
1. It should be obvious why the Object::Object(int, std::string) is called.

2. http://en.cppreference.com/w/cpp/language/copy_initialization writes:
copy initialization:
If T is a class type, and the cv-unqualified version of the type of other is not T or derived from T, or if T is non-class type, but the type of other is a class type, user-defined conversion sequences that can convert from the type of other to T (or to a type derived from T if T is a class type and a conversion function is available) are examined and the best one is selected through overload resolution. The result of the conversion, which is a prvalue temporary (until C++17)prvalue expression (since C++17) if a converting constructor was used, is then used to direct-initialize the object. The last step is usually optimized out and the result of the conversion is constructed directly in the memory allocated for the target object, but the appropriate constructor (move or copy) is required to be accessible even though it's not used. (until C++17)
To force the move constructor to be invoked: Object d = std::move( Object(10, "Steve") );
http://coliru.stacked-crooked.com/a/eb96fb6b20df4eae

Temporary materialisation: http://en.cppreference.com/w/cpp/language/implicit_conversion#Temporary_materialization
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <iostream>
using namespace std;

class Object{
public:
  Object()                     { cout << "cons\n"; }
  Object(const Object&  other) { cout << "copy cons\n"; }
  Object(      Object&& other) { cout << "move cons\n"; }
  Object& operator=(Object cp) { cout << "op =\n"; return *this; }
};
Object operator+(Object o1, Object o2) { return o1; }

int main() {
    Object a, b;
    Object c(a + b);
}

cons
cons
copy cons
copy cons
move cons

My 2 cents worth :+)

1
2
3
string* name;
// ...
name = new string(nme);


I see you have used new to obtain a pointer (maybe just for this example), try to avoid doing that - use std::addressof instead.
Topic archived. No new replies allowed.