1

I'm a beginner in C++ and I have a hard time understanding this program from an exercise book, specifically why is the empty constructor called 6 times in total:

#include <iostream>

class Allo{
 public:
   Allo(int x_=0)
    : x(x_)
   {
     std::cout << "A" << x << " ";
   }
   Allo(const Allo& autre)
    : x(autre.x)
   {
     std::cout << "B" << x << " ";
   }
   ~Allo() {
     std::cout << "C" << x << " ";
   }

   int x;
};


void f1(Allo a1, Allo* a2, Allo* a3){
   a1.x++;
   a2->x -= 1;
   a3+=1;
   (a3->x)+=2000;
}

int main(){
   Allo tab[3];
   Allo a(20);
   Allo* b = new Allo(5);
   Allo* c = tab + 1;
   f1(a, b, c);
   std::cout << std::endl << "-------" << std::endl;
   Allo* t = new Allo[4];
   t[2] = Allo(9);
   std::cout << std::endl;
   return 0;
}

And the output is :

A0 A0 A0 A20 A5 B20 C21 
-------
A0 A0 A0 A0 A9 C9 
C20 C2000 C0 C0

Showing that the empty constructor is called 4 times at the end. Why is that? Shouldn't t[2] = Allo(9); be the last line calling the constructor?

CoffeeRun
  • 71
  • 6
  • 1
    I count 4 initialized with the default of x = 0 from `Allo* t = new Allo[4];` and 1 initialized with x = 9 from `t[2] = Allo(9);` = 5 objects, matching your output. What did you expect to happen? – SuperStormer May 17 '21 at 00:34
  • I seem to count 13 constructor total while there is 17 printed total. I must be missing something but I see 3 line 1, 1 line 2, 2 line 3, 1 line 4, 5 line 7, and 1 line 8. – CoffeeRun May 17 '21 at 00:40
  • You could perhaps narrow down your confusion by commenting out lines in your `main` function. Which lines cause the "extra" default constructors to be called? Focus on those lines and (for this question) remove the other lines. It would make your question more focused and more likely to help someone else in the future. – JaMiT May 17 '21 at 02:57

1 Answers1

2

Preface: A is a regular constructor, B is a copy constructor, C is a destructor (not a constructor).

Let me break down each line:

Allo tab[3];

3 objects constructed with constructor A initalized with x = 0. These are stack allocated.

Allo a(20);

1 object constructed with A, x = 20. This is stack allocated.

Allo* b = new Allo(5);

1 object constructed with A, x = 5. This is heap allocated.

Allo* c = tab + 1;

0 objects constructed, this is the same as Allo* c = &tab[1].

f1(a, b, c);

1 object copy-constructed with B, x = 20 (since the first argument is passed by value). This object is then destructed (with C) at the end of f1 when x = 21.

std::cout << std::endl << "-------" << std::endl;
Allo* t = new Allo[4];

4 objects constructed with A, x = 0. These are heap allocated.

   t[2] = Allo(9);
   std::cout << std::endl;
   return 0;
}

1 object constructed with A, x = 9. This is stack allocated.

5 objects (all of the stack allocated objects in this function) destructed with C in reverse order of construction at the end.

SuperStormer
  • 4,997
  • 5
  • 25
  • 35
  • Interesting, that means every time a program allocates space on the stack for object constructed, it destruct it at the end even if there is no delete? – CoffeeRun May 17 '21 at 00:57
  • 1
    Yes, all stack allocated objects are automatically destructed at the end of their scope. Only heap allocated objects can and need to be `delete`'d . – SuperStormer May 17 '21 at 00:59
  • 4
    Side note: [Why are the terms “automatic” and “dynamic” preferred over the terms “stack” and “heap” in C++ memory management?](https://stackoverflow.com/questions/9181782/why-are-the-terms-automatic-and-dynamic-preferred-over-the-terms-stack-and) – user4581301 May 17 '21 at 01:01