1

My problem is, that when I'm using inheritance class, my base class is deleting 2 times (the copy from inheritance too). Is there a chance to not make a copy of base class? Or not delete it?

#include <iostream>

using namespace std;
class base {
public:
    base() { cout << "*B"; }
    ~base() { cout << "~B"; }
};

class restaurant : virtual public base {};

int main() {
    base* d1 = new base;
    restaurant restaurant;
    delete d1;
    return 0;
}

The output is *B*B~B~B but I would like to have *B*B~B because I'm not deleting restaurant, only base object.

3 Answers3

3

You're not deleteing restaurant, but you didn't new it either; it's allocated in automatic storage ("the stack"), not dynamic storage ("the heap"). Objects in automatic storage have their destructor called when they go out of scope. This is why the restaurant destructor is still being called in this case.

If you'd written:

restaurant *restaurant = new restaurant;

you'd see the behaviour you're expecting. Of course, by calling new without a matching delete you will be leaking the object, so this is not recommended.

Thomas
  • 174,939
  • 50
  • 355
  • 478
2

Firstly, objects with automatic storage are automatically deleted a the end of a scope. So declaring restaurant restaurant; will construct a restaurant but will also delete it automatically at the end of the main function.

Try this:

struct A {
    A() { std::cout << "A()"; }
    ~A() { std::cout << "~A()"; }
};

struct B : A {
    B() { std::cout << "B()"; }
    ~B() { std::cout << "~B()"; }
};

auto main() -> int {
    B b;
} // b destroyed here

The output is:

A()B()~B()~A()

It behave like a stack. First, the base class is constructed, then the derived class. Then, it destroy the derived first and the base class at the end.

This behaviour is extremely important for most C++ idiom.

Consider this:

struct A {
    A() : arr(new int[3]{1, 2, 3}) {}
    ~A() { delete[] arr; }
    int* arr = nullptr;
};

struct B : A {
    B() {}
    ~B() {}
    auto stuff() -> int {
        return std::accumulate(arr, arr + 3, 0);
    }
};

auto main() -> int {
    B b;
    return b.stuff(); // returns 1 + 2 + 3
}

What would happen if the constructor A() was not executed first? The array would be null. That would be bad.

Also... what would happen if the destructor ~A() was not executed? That would be a memory leak. That would be super bad.

Constructors and destructors have a guaranteed execution and a well defined order. This is why you don't have to call super() and ~super() in all of you constructors and destructor. Because you could forget to call it. Destructor and constructor is not something you want to forget to call, or else there would be no advantages over just using free function like in C.

Guillaume Racicot
  • 39,621
  • 9
  • 77
  • 141
  • Kind of irrelevant to your answer, but why would anyone prefer `auto main() -> int ` over `int main()` ? This makes no sense to me. – Yksisarvinen Sep 11 '19 at 14:57
  • @Yksisarvinen consistency. Sometime you don't have a choice to use trailing return types. I prefer to use it everywhere and have all my function names aligned as opposed as in some places. Same thing for `using` vs `typedef`, etc. – Guillaume Racicot Sep 11 '19 at 15:09
  • 1
    I would really like to have a `func` keyword to replace the `auto` at the begining. – Guillaume Racicot Sep 11 '19 at 15:10
0

The output is expected output. I have added comments in your main function code.

int main() {

    //Create base class object and constructor will be called
    //This object is allocated on heap
    base* d1 = new base;

    //Create derived class object
    //first constructor of base and then derived (if defined) will be called 
    //This object is allocated on stack
    restaurant restaurant;

    //Free memory and Call destructor of base class object
    delete d1;

    return 0;

    //After bracket, stack object will go out of scope and destructor will be called.
    //First derived (if defined) class destructor and then base class destructor.
}

To get expected output : *B*B~B

restaurant *restaurant = new restaurant;

But if you don't delete it then it will create memory leak in your program.

Guillaume Racicot
  • 39,621
  • 9
  • 77
  • 141