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
(anddelete[]
) are only used to delete pointers to variables allocated on the heap, using thenew
operator. In thePolygon
class, thePointArray
member isn't a pointer, it's just a member object entirely contained within thePolygon
object.You're correct that the destructor for
PointArray
is responsible for deleting thePoint *points
array in thePointArray
class. What happens is that, when the destructor of a "parent" object (likePolygon
) 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:So, the sequence in this simple case is:
~Polygon
destructor is called and is completely executed, decrementingnumPolygons
.~PointArray
destructor is called onpoints
. This deletes the underlying array owned by thePointArray
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. Thevector
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.