Take this very simple class. The main()
function just creates an object of it. Even though the constructor and destructor don't have an implementation here. My assumption is that the constructor will push the three member variables onto the stack when the object is created.
At the end of main()
the object's destructor will get implicitly called.
Is it the job of the destructor to then pop these variables off the stack?
class MyClass1
{
public:
MyClass1(){}
~MyClass1(){}
private:
int num1_ = 1;
int num2_ = 2;
int num3_ = 3;
};
int main()
{
MyClass1 mc1; // Constructor gets called
// Destructor implicitly called here as the object is going out of scope
}
No, the destructor does not pop member variables. Likewise, the constructor does not push member variables.
The job of a constructor is to initialize already-allocated storage so that, afterward, that storage contains a valid object. Symmetrically, the job of a destructor is to perform any necessary cleanup before the object's storage is reclaimed; when the destructor returns, the storage is still allocated, but does not contain a valid object anymore.
For your main()
function, when compiled by a typical compiler, the
generated object code will begin by reserving storage for mc1
on the
call stack. Normally this is done by adjusting the stack pointer
register. We don't usually refer to this as "pushing", because to
"push" there should be an existing value being pushed, whereas here,
typically, the reserved storage is left uninitialized.
Then, main()
will invoke the constructor, passing the address of the
reserved stack storage as the this
argument. For this program, the
constructor will write the values 1, 2, and 3 into the passed storage.
Next, main()
will invoke the destructor, again passing the same
address as the this
argument. For this program, the destructor will
not do anything.
Finally, main()
will reclaim the storage used by mc1
by adjusting
the stack pointer register back to what it was originally. This would
not usually be called "popping" because the values contained in the
storage are discarded.
The key point is that allocation (including on the stack) and construction are separate activities, as are deallocation and destruction.
In fact, it is possible to invoke a constructor on already-allocated storage by using the "placement new" syntax, and possible to explicitly invoke a destructor without reclaiming storage, although in both cases one must be careful not to violate the language rules and thereby cause undefined behavior.