简体   繁体   中英

Why does this destructor not have to delete the class object?

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:

  1. The ~Polygon destructor is called and is completely executed, decrementing numPolygons .
  2. The ~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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM