为什么这个析构函数不必删除 class 对象?

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

我是编程和学习 类 的初学者。我正在关注 archived online course 并为 class Polygon.

创建析构函数

answer given~Polygon 没有删除 PointArray points 的行,只包含减少 numPolygons 的行。 我假设 ~PointArray 以某种方式被激活以删除 points.

以下简化代码在 Visual Studio Community 2015 下编译。

谢谢!

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;  }

你的假设基本正确。这里有一些注意事项:

  • delete(和delete[])仅用于删除指向堆上分配的变量的指针,使用new 运算符。在Polygonclass中,PointArray成员不是一个指针,它只是一个完全包含在Polygon对象中的成员对象。

  • 你是对的,PointArray 的析构函数负责删除 PointArray class 中的 Point *points 数组。发生的事情是,当调用 "parent" 对象(如 Polygon)的析构函数时,它会自动递归调用其所有成员对象(以及所有 它们的 成员对象等)这是来自 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.

所以,这个简单例子中的顺序是:

  1. ~Polygon析构函数被调用并完全执行,递减numPolygons
  2. points 上调用了 ~PointArray 析构函数。这将删除 PointArray 对象拥有的基础数组。

如果你要删除 ~Polygon 中的 PointArray.points 指针,数组将被删除两次(一次被 ~Polygon 一次被 ~PointArray 删除),这是未定义的行为,但可能会导致崩溃。

编辑添加:作为进一步的评论,在现代 C++ 中,您可能希望使用 "smart pointer",如 std::unique_ptr,而不是"raw" 指针就像您的教程一样。这使您摆脱了这种低级内存管理的负担,因为智能指针 class 将处理超出范围时删除数组的所有细节。

第二次编辑:@user4581301 有一个更好的建议,即使用 std::vector 而不是使用指针。 vector class 将为您处理所有底层内存管理细节。它还会动态增长和收缩以处理可变大小的对象数组,而不是被限制为固定大小。