【问题标题】:Why does this destructor not have to delete the class object?为什么这个析构函数不必删除类对象?
【发布时间】:2017-05-18 05:44:09
【问题描述】:

我是编程和学习课程的初学者。我正在关注 archived online course 并为 class Polygon 创建析构函数。

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

  • 为什么我们不必在~Polygon 中输入delete[] &points;

  • 如果我的假设是正确的,PointArray 的析构函数何时以及如何生效?

  • ~Polygon 中添加delete[] &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;  }

【问题讨论】:

  • 您似乎正在使用 points = new Point[size]; 进行未定义的行为
  • PointsArray 应该有一个重载的operator= 成员函数以符合rule of three
  • @DanielA.White 你是什么意思?
  • @PaulRooney 谢谢!我还没有学习复制赋值运算符。

标签: c++ class destructor new-operator delete-operator


【解决方案1】:

你的假设基本上是正确的。以下是一些注意事项:

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

  • 你说得对,PointArray 的析构函数负责删除 PointArray 类中的 Point *points 数组。发生的情况是,当调用“父”对象(如Polygon)的析构函数时,它会自动递归调用其所有成员对象(以及所有它们的成员对象的析构函数,等)这是来自cppreference的相关部分:

对于用户定义的或隐式定义的析构函数,在执行析构函数的主体后,编译器为类的所有非静态非变体成员调用析构函数,以声明的相反顺序,然后它以相反的构造顺序调用所有直接非虚拟基类的析构函数(依次调用其成员及其基类的析构函数等),然后,如果该对象是最-派生类,它调用所有虚基的析构函数。

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

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

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

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

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

【讨论】:

  • 建议:附上关于使用 std::vector 或类似容器而不是动态分配的数组的注释,即使受到智能指针的保护,只是因为它们更容易处理三规则和五规则。跨度>
  • 谢谢!这很有帮助。
猜你喜欢
  • 2019-01-29
  • 2021-11-05
  • 1970-01-01
  • 2011-03-16
  • 2014-04-22
  • 2013-09-30
  • 1970-01-01
  • 2012-04-30
  • 2012-09-01
相关资源
最近更新 更多