1

I am starting to work with nested classes and I am not sure I understand them yet. I have the following code:

#include <iostream>
#include <string>

class enclose
{
    private:
        int x;
    public:
        enclose(void);
        ~enclose(void);

        class nested1
        {
            public:
                nested1(void);
                ~nested1(void);
                void printnumber(enclose p);
        };

        nested1 nested;

};

enclose::enclose(void)
{
    std::cout << "Enclosed class constructor called" << std::endl;
    this->x = 10;
}

enclose::~enclose(void)
{
    std::cout << "Enclosed class destructor called" << std::endl;
}

enclose::nested1::nested1(void)
{
    std::cout << "Nested class constructor called" << std::endl;
}

enclose::nested1::~nested1(void)
{
    std::cout << "nested class destructor called" << std::endl;
}


void    enclose::nested1::printnumber(enclose p)
{
    std::cout << "the number is " << p.x << std::endl;
}

int main()
{
    enclose example;

    example.nested.printnumber(example);
}

The output of my code is the following:

Nested class constructor called
Enclosed class constructor called
the number is 10
Enclosed class destructor called
nested class destructor called
Enclosed class destructor called
nested class destructor called

How can destructors be called twice if constructors are only called once? I thought you couldn't destruct something that hasn't been constructed previously.

kubo
  • 221
  • 1
  • 8
  • 6
    `printnumber` accepts it's argument by value which makes a copy when called. That object is destroyed when the function ends. – Retired Ninja Sep 10 '21 at 11:16
  • 9
    You don't print all possible ways to construct your class, particularly the copy constructor. – jamesdlin Sep 10 '21 at 11:17
  • 1
    For reference: [implicitly declared copy constructor](https://en.cppreference.com/w/cpp/language/copy_constructor#Implicitly-declared_copy_constructor) – spectras Sep 10 '21 at 11:18
  • Does this answer your question? [Why is the destructor of the class called twice?](https://stackoverflow.com/questions/2627540/why-is-the-destructor-of-the-class-called-twice) – asynts Sep 10 '21 at 12:20
  • *How can destructors be called twice if constructors are only called once?* They can't, and attempting to do so is **undefined behavior**. The code provided does not do that. – Eljay Sep 10 '21 at 13:51

2 Answers2

0

Because you are passing a copy of example to enclose::nested1::printnumber(...).

That is, example.nested.printnumber(example) passes example by value and example is an instance of a class, that means to copy it. The copy's destructor will fire too.

Change the signature of printnumber to void enclose::nested1::printnumber(const enclose& p) and see if you get the results you expect.

jwezorek
  • 8,592
  • 1
  • 29
  • 46
0

To get a better view, further instrument the constructors (including copy constructor) and destructor to show the address of the object being called upon.

Then, you will see that each object is constructed and eventually destructed, and meanwhile different instances are also constructed and destructed.

E.g.

enclose::enclose (const enclose& other)
: x{other.x}
{
    std::cout << "Enclosed class copy constructor called for instance "
        << this
        << '\n';
}

It is helpful to make a header file with a fully instrumented class, called noisy or something like that. It has no data members and serves only to output when it is created, copied, and destroyed.

This is useful because it doesn't need to do any real work in those special members, and you can reuse this in any class you want. You can inherit it from both enclose and nested1 without duplicating your work.


void printnumber(enclose p);
Generally, remember to pass complex types by reference. So you would normally declare this function as void printnumber (const enclose& p);.


BTW:

Don't write (void) to mean (). That's something added to ANSI C when it got C++-style function declarations but needed to still support the old way. Stroustrup calls it "an abomination".

Don't write this-> for your member access. The members are in scope and don't need to be qualified in any way.

Don't use std::endl. Just output a \n when you want a newline.

JDługosz
  • 5,592
  • 3
  • 24
  • 45