Need help understanding why certain constructors and assignments are called when compiler creates rvalues.

I am trying to learn when and why constructors, assignments, and destructors are called in c++. I created a few sample codes to practice and I will tell you which parts I don't understand and I will also tell you what is printed when compiling and running the codes. I am compiling and running in ubuntu's terminal and using the flags -std=c++11 and -fno-elide-constructors so that the terminal prints every constructor.

CODE A:
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
#include<iostream>
#include<string>

class MyClass{
private:
  std::string name;
public:
  MyClass(const std::string & ="default");
  MyClass(const MyClass &);
  MyClass(MyClass &&);
  void operator=(const MyClass &);
  void operator=(MyClass &&);
  ~MyClass();
};

MyClass::MyClass(const std::string & _Name){
  name=_Name;
  std::cout<<"DEFAULT CONSTRUCTOR for " <<name <<std::endl;
}

MyClass::MyClass(const MyClass & copyFrom){
  std::cout<<"COPY CONSTRUCTOR for " <<name <<std::endl;
}

MyClass::MyClass(MyClass && moveFrom){
  std::cout<<"MOVE CONSTRUCTOR for " <<name <<std::endl;
}

void MyClass::operator=(const MyClass & copyFrom){
  std::cout<<"COPY ASSIGNMENT for " <<name <<std::endl;
}

void MyClass::operator=(MyClass&& moveFrom){
  std::cout<<"MOVE ASSIGNMENT for " <<name <<std::endl;
}

MyClass::~MyClass(){
  std::cout<<"DESTRUCTOR for " <<name <<std::endl;
}

MyClass myFunction(){
  MyClass temp("temporary");
  return temp;
}

void heavyPrinting(){
  MyClass object1("first");
  MyClass object2("second");
  object1=object2;
  MyClass object3("third");
  std::cout<<"FUNCTION CALLING" <<std::endl;
  object3=myFunction();
  std::cout<<"FUNCTION FINISHED" <<std::endl;
  std::cout<<"7" <<std::endl;
}

int main(){
  heavyPrinting();
  std::cout<<std::endl;
  return 0;
}


PRINTS:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
DEFAULT CONSTRUCTOR for first
DEFAULT CONSTRUCTOR for second
COPY ASSIGNMENT for first
DEFAULT CONSTRUCTOR for third
FUNCTION CALLING
DEFAULT CONSTRUCTOR for temporary
MOVE CONSTRUCTOR for 
DESTRUCTOR for temporary
MOVE ASSIGNMENT for third
DESTRUCTOR for 
FUNCTION FINISHED
7
DESTRUCTOR for third
DESTRUCTOR for second
DESTRUCTOR for first


I understand why everything is called before "FUNCTION CALLING" and after "FUNCTION FINISHED" but I am not sure about the part inside the function. Is "MOVE CONSTRUCTOR for" creating a temporary rvalue? Then "MOVE ASSIGNMENT for third" comes from the line in main "object3=myFunction();" I think. Then "DESTRUCTOR for" is destroying the rvalue. Is this correct? Why is c++ creating a temporary object in the function when the function doesn't do anything?

CODE B:
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
#include<iostream>
#include<string>

class MyClass{
private:
  std::string name;
public:
  MyClass(const std::string & ="default");
  MyClass(const MyClass &);
  MyClass(MyClass &&);
  void operator=(const MyClass &);
  void operator=(MyClass &&);
  ~MyClass();
};

MyClass::MyClass(const std::string & _Name){
  name=_Name;
  std::cout<<"DEFAULT CONSTRUCTOR for " <<name <<std::endl;
}

MyClass::MyClass(const MyClass & copyFrom){
  std::cout<<"COPY CONSTRUCTOR for " <<name <<std::endl;
}

MyClass::MyClass(MyClass && moveFrom){
  std::cout<<"MOVE CONSTRUCTOR for " <<name <<std::endl;
}

void MyClass::operator=(const MyClass & copyFrom){
  std::cout<<"COPY ASSIGNMENT for " <<name <<std::endl;
}

void MyClass::operator=(MyClass&& moveFrom){
  std::cout<<"MOVE ASSIGNMENT for " <<name <<std::endl;
}

MyClass::~MyClass(){
  std::cout<<"DESTRUCTOR for " <<name <<std::endl;
}

MyClass myFunction(MyClass obj){
  return obj;
}

void heavyPrinting(){
  MyClass object1("first");
  MyClass object2("second");
  object1=object2;
  MyClass object3("third");
  std::cout<<"FUNCTION CALLING" <<std::endl;
  object3=myFunction(object3);
  std::cout<<"FUNCTION FINISHED" <<std::endl;
  std::cout<<"7" <<std::endl;
}

int main(){
  heavyPrinting();
  std::cout<<std::endl;
  return 0;
}


PRINTS:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
DEFAULT CONSTRUCTOR for first
DEFAULT CONSTRUCTOR for second
COPY ASSIGNMENT for first
DEFAULT CONSTRUCTOR for third
FUNCTION CALLING
COPY CONSTRUCTOR for 
MOVE CONSTRUCTOR for 
MOVE ASSIGNMENT for third
DESTRUCTOR for 
DESTRUCTOR for 
FUNCTION FINISHED
7
DESTRUCTOR for third
DESTRUCTOR for second
DESTRUCTOR for first


Again, here I understand everything that is called outside the function, what I don't understand is why "COPY CONSTRUCTOR for", "MOVE CONSTRUCTOR for", and the two "DESTRUCTOR for" are called? Can someone explain to me what the compiler is doing inside the function?

Thank you.
Your move assignment is not actually implemented. Try something on the lines of:
1
2
3
4
5
6
7
#include <utility> //std::move()
//
MyClass::MyClass(MyClass && moveFrom){
  name = std::move(moveFrom.name);
  std::cout<<"MOVE CONSTRUCTOR for " <<name <<std::endl;
//I used a struct with public access specifiers instead of class 
}

You'll find the results are quite different in this case, viz:
1
2
3
4
5
6
7
8
9
10
11
12
13
DEFAULT CONSTRUCTOR for first
DEFAULT CONSTRUCTOR for second
COPY ASSIGNMENT for first
DEFAULT CONSTRUCTOR for third
FUNCTION CALLING
DEFAULT CONSTRUCTOR for temporary
MOVE ASSIGNMENT for third
DESTRUCTOR for temporary
FUNCTION FINISHED
7
DESTRUCTOR for third
DESTRUCTOR for second
DESTRUCTOR for first

Does this make (a bit) more sense?

And don't forget that this function:
1
2
3
MyClass myFunction(MyClass obj){
  return obj;
}

Is using pass by value, which means that a copy of the parameter will be made, to avoid the automatic copy pass by reference/const reference.

Topic archived. No new replies allowed.