elyashiv
elyashiv

Reputation: 3691

why code calls destructor twice?

I have taken a look at this presentation, and at slide 379, it shows the following code (with a few minor changes):

#include <iostream>
using namespace std;

struct A
{
    A() { cout << "A()" << endl; }
    A(int v) { cout << "A(int)" << endl; }
    ~A() { cout << "~A()" << endl; }
};

struct X
{
    X(int v) { a = v; }
    X(long v) : a(v) {}
    A a;
};

int main()
{
    cout << "bad style:" << endl;
    { X slow(int(2)); }
    cout << "good style:" << endl;
    { X fast(long(2)); }
}

the output is:

bad style:
A()
A(int)
~A()
~A()
good style:
A(int)
~A()

(this code was run on my machine, compiled with g++)

Now, I understood why the constructor will be called twice in the bad style, but why will the destructor do so?

Upvotes: 1

Views: 191

Answers (4)

Yury Schkatula
Yury Schkatula

Reputation: 5369

You fallen a victim of "implicit typecast". Try to add "explicit" to your constructors and would see what's wrong in your code (it will stop compiling at the place of the former implicit conversion):

struct A
{
    explicit A() { cout << "A()" << endl; }
    explicit A(int v) { cout << "A(int)" << endl; }
    ~A() { cout << "~A()" << endl; }
};

Here is an explanation: http://en.cppreference.com/w/cpp/language/implicit_cast

Upvotes: 1

umlcat
umlcat

Reputation: 4143

Intro

There is an additional thing to consider, when executing constructors & destructors in C++.

Are you declaring a static allocated object or a dynamic allocated object ?

Static Allocation

#include <iostream>
using namespace std;

class A {
public:
    // constructors
    A() { cout << "A()" << endl; }
    A(int v) { cout << "A(int)" << endl; }

    // destructors
    ~A() { cout << "~A()" << endl; }
};

class X {
public:
    // constructors
    X(int v) { a = v; }
    X(long v) : a(v) {}

    // variables
    A a;
};

int main()
{
    cout << "bad style:" << endl;
    X slow(int(2));

    cout << "good style:" << endl;
    X fast(long(2));
}

Dynamic Allocation

#include <iostream>
using namespace std;

class A {
public:
    // constructors
    A() { cout << "A()" << endl; }
    A(int v) { cout << "A(int)" << endl; }

    // destructors
    ~A() { cout << "~A()" << endl; }
};

class X {
public:
    // constructors
    X(int v) { a = new(v); }
    X(long v) : { a = new(); *a = v; }

    // destructors
    ~X() { delete a; }

    // variables
    A* a;
};

int main()
{
    cout << "bad style:" << endl;
    X slow = new X(int(2));

    cout << "good style:" << endl;
    X fast = new (long(2));

    // do something else with "X"

    delete slow();
    delete fast();
}

Summary

Static allocated variables call destructors automatically, while dynamic allocated variables that use pointers, you need to explicitly call the destructor.

** Extra**

If you have previously use another Object Oriented language, or have to switch from C++ to another, this is important to consider, because maybe handle different.

Upvotes: 0

Tony
Tony

Reputation: 17657

The logic is

Instantiate a Class    ... +1 [Constuctor]
Desinstantiate a Class ... -1 [Destructor]

A destructor is called for a class object when that object passes out of scope or is explicitly deleted.

So you can expect that The Destructors of the classes will be called an equal number of times these Classes were created.

Upvotes: 1

jrok
jrok

Reputation: 55425

X(int v) { a = v; }
//         ^^^^^

The underlined line is an assignment. There's no operator= that takes an int (v), but there's an implicit conversion from int to A. So, a temporary object of type A is constructed and passed to assignment operator that the compiler generated for you. It gets destructed later (after the full expression it was created in ends) and there's your second destructor you didn't expect.

Upvotes: 8

Related Questions