To give an object more permanence it has to be placed on the heap. To demonstrate this start up ROOT and load the Quad class:-
Quad* my_objptr = new Quad(1., 2., -3.);Picking this apart:-
There is no FORTRAN parallel to a heap object; variables either come and go as control passes in and out of a function or subroutine, or, like a COMMON block variables, live for the lifetime of the program. However, most people in HEP who use FORTRAN will have experience of a memory manager and the act of creating bank is a good equivalent of a heap object. For those who know systems like ZEBRA, it will come as a relief to learn that objects don't move, C++ does not garbage collect, so there is never a danger that a pointer to an object becomes invalid for that reason. However, having created an object, it is the user's responsibility to ensure that it is deleted when no longer needed, or to pass that responsibility onto to some other object. Failing to do that will result in a memory leak
To send a message to an object via a pointer to it, you need to use the -> operator e.g.:-
As we have seen, heap objects have to be accessed via pointers, whereas stack objects can be accessed directly. They can also be accessed via pointers:-
Quad stack_quad(1.,2.,-3.); Quad* stack_ptr = &stack_quad; stack_ptr->Solve();Here we have a Quad pointer that has been initialised with the address of a stack object. Be very careful if you take the address of stack objects. As we shall see soon, they get deleted automatically which could leave you with an illegal pointer. Using it will be corrupt and may well crash the program!
It is time to look at the destruction of objects. Just as its constructor is called when it is created, so its destructor is called when it is destroyed. The compiler will provide a destructor that does nothing if none is provided. We will add one to our Quad class so that we can see when it gets called.
If you are running ROOT then exit and then edit the two files Quad.h and Quad.cxx as shown in red
Quad.h class Quad { public: Quad(Float_t a, Float_t b, Float_t c); ~Quad(); Float_t Evaluate(Float_t x) const; void Solve() const; private: Float_t fA; Float_t fB; Float_t fC; }; Quad.cxx #include <iostream.h> #include <math.h> #include "Quad.h" Quad::Quad(Float_t a, Float_t b, Float_t c) { fA = a; fB = b; fC = c; } Quad::~Quad() { cout << "deleting object with coeffts: " << fA << "," << fB << "," << fC << endl; } Float_t Quad::Evaluate(Float_t x) const { return fA*x*x + fB*x + fC; } void Quad::Solve() const { Float_t temp = fB*fB - 4.*fA*fC; if ( temp > 0. ) { temp = sqrt( temp ); cout << "There are two roots: " << ( -fB - temp ) / (2.*fA) << " and " << ( -fB + temp ) / (2.*fA) << endl; } else { if ( temp == 0. ) { cout << "There are two equal roots: " << -fB / (2.*fA) << endl; } else { cout << "There are no roots" << endl; } } }The destructor is named by the class but with the prefix ~ which is the C++ one's complement i.e. bitwise complement, and hence has destruction overtones! We declare it in the .h and define it in the .cxx. It does not do much except print out that it has been called (still a useful debug technique despite today's powerful debuggers!). Now run root, load the Quad class and create a heap object:-
delete my_objptr; my_objptr = 0;You should see the print out from its destructor. Setting the pointer to zero afterwards isn't strictly necessary (and CINT does it automatically), but the object is no more, and any attempt to use the pointer again will, as has already been stated, cause grief.
So much for heap objects, but how do stack objects get deleted? In C++ a stack object is deleted as soon as control leaves the innermost compound statement that encloses it. So it is singularly futile to do something like:-
On the stack: My_class my_object(arglist); On the heap: My_class* my_objptr = new My_class(arglist);
my_objptr->Message(arg_list);
~My_class
delete my_objptr;