Order Of Execution Of Constructor & Destructor
The creation of an object of its related class calls constructors. Constructor-created items are destroyed by destructors. The length of time and scope of the object’s storage determine the order of execution:
Global Objects
- Global object constructors are run before main() starts running. A source file’s global objects are initialized in the order in which they are defined if there are several.
- Upon the termination of main(), global object destructors run in reverse order.
Automatic Objects (Stack-allocated)
- When the declaration statement for the object is encountered, local object constructors are run.
- The variable exits scope when local object destructors are called. The code block that defined them ends here.
- Destructors for objects in the same scope are invoked in reverse order of construction. This applies whether an exception is raised or the function terminates normally.
- Destructors are called at the end of each loop iteration (in reverse order of creation), creating objects declared in looping expressions (such as while, for) when the loop restarts.
Dynamically Allocated Objects (Heap-allocated)
- Its constructor is called when formed with the new operator.
- Only when the delete operator is applied to a dynamically allocated object’s pointer is its destructor triggered. In arrays allocated using new[], delete[] ensures each element calls the destructor.
Member Objects
- When an object that contains member objects is initialized, the constructor for the entire object is constructed and initialized after the member objects. Members are initialized not in the order they appear in the constructor initializer list, but rather in the order they are specified in the class definition.
- The members are destroyed when the function body has been executed in a destructor. Members are eliminated in the opposite order that they were initially created. There is no action taken to destroy members of built-in types since they lack destructors.
Passing/Returning Objects by Value
- The stack of the called function is copied when an item is supplied by value to the function. The copy does not call the constructor for the original object again.
- Nevertheless, after the called function finishes, the destructor for this copy is invoked. When the default bitwise copy is used when the object controls resources (such dynamic memory), it can cause problems because both the original and the copy would try to free the same memory, which could harm the original. The solution to this issue is to define a copy constructor.
Code Example Demonstrating Destructor Execution Order
#include <iostream> // For input/output operations
#include <string> // For using std::string
// A simple class to demonstrate constructor and destructor calls
class MyObject {
public:
std::string name;
// Constructor: Called when an object is created
MyObject(const std::string& n) : name(n) {
std::cout << "Constructor: " << name << " created." << std::endl;
}
// Destructor: Called when an object is destroyed
// Marked with '~' and takes no arguments, returns no value
~MyObject() {
std::cout << "Destructor: " << name << " destroyed." << std::endl;
}
};
// Global object: Its constructor is called before main() [53-55], and destructor after main() finishes.
MyObject global_obj("GlobalObject");
int main() {
std::cout << "\n--- Entering main() function ---" << std::endl;
// Local object (stack-allocated): Its constructor is called when declared.
// Its destructor is called when main() scope ends.
MyObject local_obj1("LocalObject1");
{ // Start of an inner block (new scope)
std::cout << "\n--- Entering inner block ---" << std::endl;
// Another local object: Its destructor is called when this inner block ends.
MyObject local_obj2("LocalObject2");
MyObject local_obj3("LocalObject3"); // Constructed after local_obj2
std::cout << "--- Exiting inner block ---" << std::endl;
} // local_obj3 and local_obj2 go out of scope here.
// Destructors are called in reverse order of creation: local_obj3 then local_obj2.
std::cout << "\n--- Back in main() after inner block ---" << std::endl;
// Dynamically allocated object: Constructor called by 'new'.
// Destructor called explicitly by 'delete'].
MyObject* dynamic_obj = new MyObject("DynamicObject");
std::cout << "--- Deleting dynamic_obj ---" << std::endl;
delete dynamic_obj; // Explicitly calls the destructor for DynamicObject.
std::cout << "\n--- Exiting main() function ---" << std::endl;
return 0;
} // local_obj1 goes out of scope here; its destructor is automatically invoked.
// After main() completes, global_obj destructor is invoked.
Output
Constructor: GlobalObject created.
--- Entering main() function ---
Constructor: LocalObject1 created.
--- Entering inner block ---
Constructor: LocalObject2 created.
Constructor: LocalObject3 created.
--- Exiting inner block ---
Destructor: LocalObject3 destroyed.
Destructor: LocalObject2 destroyed.
--- Back in main() after inner block ---
Constructor: DynamicObject created.
--- Deleting dynamic_obj ---
Destructor: DynamicObject destroyed.
--- Exiting main() function ---
Destructor: LocalObject1 destroyed.
Destructor: GlobalObject destroyed.
You can also read Default And Parameterized Constructors In C++ With Examples