when do destructors get called

In the program below I've inserted some output to try and help me follow the program execution. I don't understand what points in the program are calling the destructor of the TestRun class and why. I commented out some of the destructor code to keep it from erroring until I understand what's happening.

I would be very grateful if someone could explain it to me. Thanks.

Here is the output :
TestHeader constructor
TestSet constructor
TestRun(int) constructor

test added successfully
TestRun destructor

test added successfully
TestRun destructor
TestRun destructor

test added successfully

test added successfully
TestRun destructor
TestRun destructor
TestRun destructor
TestRun destructor

test added successfully
TestRun destructor
TestSet destructor
TestRun destructor
TestRun destructor
TestRun destructor
TestRun destructor
TestRun destructor
TestHeader destructor


Main test program :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <iostream>
#include "testset.h"

using namespace std;

int main()
{
    TestSet currTest;
    TestRun tst(900);
    for( int i = 1; i <= 5; i++ )
    {
        if (currTest.addRun(tst))
            cout << "\ntest added successfully\n";
    }
    return 0;
}


header file :
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
class TestHeader
{
	public:
		TestHeader();
		~TestHeader();
	protected:
        vector<string> headerData;
	private:
};


class TestRun
{
    public:
        TestRun();
        TestRun(int);
        ~TestRun();
    private:
	    double *angle;
        double *torque;
        double *tension;
        double *reaction;
};

class TestSet
{
	public:
		TestSet();
		~TestSet();
		bool addRun(TestRun &);
		bool deleteRun();
		int runCount();
    protected:

    private:
        TestHeader TestInfo;
        vector<TestRun> testRuns;
};


implementation :
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
62
63
64
65
66
TestHeader::TestHeader()
{
    headerData.push_back("one");
    headerData.push_back("two");
    headerData.push_back("three");
    cout << "TestHeader constructor\n";
}

TestHeader::~TestHeader()
{
    cout << "TestHeader destructor\n";
}

TestRun::TestRun()
{
    angle = new double[500];
    torque = new double[500];
    tension = new double[500];
    reaction = new double[500];
    cout << "TestRun constructor\n";
}

TestRun::TestRun(int ms)
{
    angle = new double[ms];
    torque = new double[ms];
    tension = new double[ms];
    reaction = new double[ms];
    cout << "TestRun(int) constructor\n";
}
TestRun::~TestRun()
{
//    delete [] angle;
//    delete [] torque;
//    delete [] tension;
//    delete [] reaction;
    cout << "TestRun destructor\n";
}

bool TestSet::addRun(TestRun &tr)
{
    testRuns.push_back(tr);
    return true;
}

bool TestSet::deleteRun()
{
    testRuns.pop_back();
    return true;
}
int TestSet::runCount()
{
    return static_cast<int>(testRuns.size());
}

TestSet::TestSet()
{
    // some stuff goes here
    cout << "TestSet constructor\n";
}

TestSet::~TestSet()
{
    // some stuff goes here
    cout << "TestSet destructor\n";
}
I think I see what is going on here:
In your TestSet Class you have a vector <testRun> variable
and a function
1
2
3
4
5
bool TestSet::addRun(TestRun &tr)
{
    testRuns.push_back(tr);
    return true;
}


The vector has initial size of 0 (zero) elements so each time you do the push.back the vector has to reallocate space for it, which means that it creates a new vector space, copies the elements from the old space and has to destroy the previous copies which means that the destructor gets called for each TestRun variable.

This explains why you get that strange pattern of TestRun destructor calls
for example when the first testRun is added there are no previous ones to delete.

When the second one is added the old copy of the first one is destructed.
(one destructor call)

when the third one is added , old copies of the previous two are destructed
(two destructor calls).

as so it goes on.


The way around this is to maybe reserve some intial vector space say enough for 10 (ten) testRuns like this:

1
2
3
4
5
6
7
8
TestSet::TestSet()
{
    // some stuff goes here

     testRuns.reserve(10); //initial space allocation for 10 testRuns
    cout << "TestSet constructor\n";
}


and you will see a difference.

Thanks.

I did see a difference. Each time the call was made to add a TestRun I got the constructor then destructor. I still erred in the end though. I think there was a call to the destructor for each item added to the vector.
Topic archived. No new replies allowed.