Introduction
A constructor is a member function with the class's own name and no return type. It runs automatically when an object is created, so an object is never left half set up. A destructor, ~ClassName(), runs automatically when the object dies.
An object should be ready to use from the moment it exists, and should clean up after itself when it goes. Constructors and destructors make both of those happen automatically, without any call you could forget.
How it works
Constructors
#include <iostream>
using namespace std;
class Point {
int x, y;
public:
Point() : x(0), y(0) {}
Point(int x, int y) : x(x), y(y) {}
void print() const {
cout << "(" << x << ", " << y << ")" << endl;
}
};
int main() {
Point origin;
Point p(3, 4);
Point q = Point(-1, 2);
origin.print();
p.print();
q.print();
return 0;
}Point()is the default constructor: it runs forPoint origin;.Point(int x, int y)runs forPoint p(3, 4);. Several constructors overload each other, like any functions.: x(x), y(y)is the member initializer list: it gives each member its first value before the body runs. Inx(x), the outerxis the member and the one in brackets is the parameter.
If a class declares no constructor at all, the compiler writes a default one that leaves int and double members uninitialized (garbage, as in C). As soon as you write any constructor, that free default one is gone: Point origin; then needs a Point() of your own.
Syntax
class Box {
int size;
public:
Box() : size(0) {} // default constructor
Box(int s) : size(s) {} // constructor with a parameter
~Box() { /* release resources */ }
};
Example
#include <iostream>
#include <string>
using namespace std;
class Tracker {
string name;
public:
Tracker(string n) : name(n) {
cout << "built " << name << endl;
}
~Tracker() {
cout << "destroyed " << name << endl;
}
};
int main() {
Tracker a("a");
{
Tracker b("b");
Tracker c("c");
}
Tracker d("d");
return 0;
}A local object is destroyed when its block ends, at the closing }. Objects in the same block die in reverse order of creation: c before b. Watch the call stack: Tracker::Tracker frames appear as objects are made, and Tracker::~Tracker frames when they die. d and a are destroyed when main ends.
Destructors matter for objects that own something: memory from new, an open file, a network connection. The destructor releases it, so the object cleans up after itself, however the block is left. This idea is called RAII (resource acquisition is initialization), and it is how string and vector manage their memory.
Line by line
Trackerstores a name, and its constructor uses the initializer list: name(n)to set it.- The constructor prints
built, and the destructor~Tracker()printsdestroyed. ais created first, at the top ofmain.- The inner block creates
band thenc. At its closing}, they are destroyed in reverse order:cfirst, thenb. dis created after the block ends.- When
mainreturns,dandaare destroyed, again newest first.
Expected result
built a
built b
built c
destroyed c
destroyed b
built d
destroyed d
destroyed a
In the real world
File streams close their file in their destructor, and locks in multithreaded code are released by a destructor. This is why C++ code rarely needs a "finally" step: leaving the block is enough to clean up.
Common mistakes
- Writing
Point p();to call the default constructor: it declares a function namedp. WritePoint p;. - Giving a constructor a return type, even
void. - Initializing members in the wrong order: they are initialized in the order they are declared in the class, not the order in the list.
Best practices
- Initialise every member in the initializer list.
- Write the initializer list in the same order as the members are declared.
- Give a class a destructor whenever it owns something that must be released.
Summary
Constructors set up an object as it is created, ideally with a member initializer list, and destructors clean up when it is destroyed. Local objects die at the end of their block in reverse order, which is the basis of RAII.
Quick check
Key takeaways
- A constructor makes sure an object is never half set up.
- Local objects are destroyed at the end of their block, newest first.
- A destructor releases what the object owns.
Practice problems for this lesson
My notes
Write down what you want to remember from this lesson. Notes are saved on this device as you type, and appear on your dashboard.