I'm a beginner at programming and learning about classes. I'm following an archived online course and making a destructor for the class Polygon
.
The answer given has ~Polygon
without a line to delete the PointArray points
, only containing a line to decrement numPolygons
.
I would assume that ~PointArray
is activated somehow to delete the points
.
Why do we not have to delete[] &points;
in ~Polygon
?
If my assumption is correct, when and how does PointArray's destructor go into effect?
How would having delete[] &points;
in ~Polygon
affect the program?
The following simplified code compiles under Visual Studio Community 2015.
Thank you!
class Point {
private: int x, y;
public:
Point(int x = 0, int y = 0) {
this->x = x; // initializes (*this).x with x
this->y = y; // initializes (*this).y with x
}
// other member functions...
};
class PointArray {
int len;
Point *points;
public:
PointArray() {
len = 0;
points = new Point[0];
}
PointArray(const Point copyPoints[], const int size) {
points = new Point[size];
len = size;
for (int i = 0; i < size; ++i) points[i] = copyPoints[i];
}
PointArray(const PointArray &pv) {
len = pv.len;
points = new Point[len];
for (int i = 0; i < len; ++i) points[i] = pv.points[i];
}
~PointArray() {
delete[] points;
}
// other member functions...
};
class Polygon {
protected:
PointArray points;
static int numPolygons; // tracks # of Polygon instances/objects
public:
Polygon(const Point pointArr[], const int numPoints)
: points(pointArr, numPoints) { // initializes internal PointArray
++numPolygons; // +1 (initialized)
}
Polygon(const PointArray &pa)
: points(pa) { // initializes internal PointArray with arg
++numPolygons;
}
~Polygon() {
//delete[] &points;
--numPolygons;
}
};
int main() { return 0; }
Your assumption is basically correct. Here are a couple of notes:
delete
(and delete[]
) are only used to delete pointers to variables allocated on the heap, using the new
operator. In the Polygon
class, the PointArray
member isn't a pointer, it's just a member object entirely contained within the Polygon
object.
You're correct that the destructor for PointArray
is responsible for deleting the Point *points
array in the PointArray
class. What happens is that, when the destructor of a "parent" object (like Polygon
) is called, it automatically recursively calls the destructors for all of its member objects (and all of their member objects, etc.) Here's a relevant section from cppreference:
For both user-defined or implicitly-defined destructors, after the body of the destructor is executed, the compiler calls the destructors for all non-static non-variant members of the class, in reverse order of declaration, then it calls the destructors of all direct non-virtual base classes in reverse order of construction (which in turn call the destructors of their members and their base classes, etc), and then, if this object is of most-derived class, it calls the destructors of all virtual bases.
So, the sequence in this simple case is:
~Polygon
destructor is called and is completely executed, decrementing numPolygons
.~PointArray
destructor is called on points
. This deletes the underlying array owned by the PointArray
object.If you were to delete the PointArray.points
pointer in ~Polygon
, the array would get deleted twice (once by ~Polygon
and once by ~PointArray
), which is undefined behavior but will likely result in a crash.
Edit to add: as a further comment, in modern C++, you would likely want to use a "smart pointer" like std::unique_ptr
, rather than a "raw" pointer like your tutorial is doing. That frees you from the burden of this kind of low-level memory management, since the smart pointer class will handle all of the details of deleting the array when it goes out of scope.
Second edit: @user4581301 has an even better suggestion, which is to use std::vector
rather than bothering with pointers at all. The vector
class will handle all the underlying memory management details for you. It will also dynamically grow and shrink to handle variably-sized arrays of objects, rather than being constrained to a fixed size.