删除与其他人共享的指针 class

Deleting Pointer shared with other class

我在使用 类.

之间共享的指针在 c++ 中重新分配内存时遇到问题

一个例子:

我的顶点定义为:

class Vertex{
    double x;
    double y;
}

正方形定义为:

class Square{
    Square(Vertex* a, Vertex* b, Vertex* c, Vertex* d);
    ~Square(); // destructor
    Vertex* a;
    Vertex* b;
    Vertex* c;
    Vertex* d;
}

我的析构函数是这样实现的:

Square::~Square(){
    delete a;
    delete b;
    delete c; 
    delete d;
}

我的方块存储在 std::vector<Square*> squares 中,所以为了清理我的所有内存,我会这样做:

for(unsigned int i = 0; i < squares.size(); i++){
    delete(squares.at(i));
}

那么问题是什么?如果两个正方形共享一个顶点,我的程序就会崩溃,因为它试图删除一个不再存在的指针。 我怎么解决这个问题?

在我看来,您正在以类似 Java 的思维方式使用 C++ 进行编码。 Vertex 只包含两个 double 的对象(例如你的情况下的 X 和 Y 组件)最好存储在堆栈中,没有指针间接。所以,我会这样声明 Square class:

class Square{
...
  Vertex a;
  Vertex b;
  Vertex c;
  Vertex d;
};

如果您想要一种引用机制而不是嵌入 Vertex 对象,您可以将顶点存储在 std::vector<Vertex> 数组中,然后存储在 Square class integer indexes 到数组中的顶点位置。

如果您真的想要指针的共享所有权语义,请考虑使用智能指针,例如std::shared_ptr。没有显式 delete: shared_ptr 将在引用计数达到零时 自动 释放内存。

在这种情况下,将原始 Vertex* 拥有指针数据成员替换为 shared_ptr<Vertex> 在您的 Square class 中。此外,从 Square class 中删除析构函数代码,因为 shared_ptr 知道如何删除自身。

在你的 Square class 构造函数中,你可以按值获取 shared_ptr<Vertex> 智能指针,并 std::move 它们在相应的数据成员中,例如:

Square::Square(
  std::shared_ptr<Vertex> pa,
  std::shared_ptr<Vertex> pb,
  std::shared_ptr<Vertex> pc
)
  : a{std::move(pa)}
  , b{std::move(pb)}
  , c{std::move(pc)}
{}

也将 vector<Square*> 替换为 vector<shared_ptr<Square>>(但是,再次强调,您确定更简单的 vector<Square> 不适合您吗?),并使用 std::make_shared创建智能指针。

你永远不应该在现代 C++ 中手动分配内存,除非你有很好的理由这样做。如果您的 Square class 想要对 Vertex 个实例的 共享所有权 建模,那么您应该使用 std::shared_ptr:

class Square{
    // ...
    std::shared_ptr<Vertex> a, b, c, d;
}

不过,我建议您重新考虑将动态内存分配用于像 Vertex 这样简单和轻量级的东西。

如果您使用的是遗留代码并且您不能将原始指针更改为共享指针或者您不能简单地复制顶点(您想引用原始对象),那么不要在 Square 析构函数中删除顶点,并可能使用对顶点的引用而不是指针。

您已经在 Square 对象外部管理 Vertexes 的分配,因此请确保仅在所有 Square 都消失后才释放顶点。

代码流程如下所示:

  • 所有顶点都已分配:容器跟踪所有顶点
  • 在多个对象中使用顶点,可能通过对它们的引用
  • 当使用顶点的所有对象都消失后,释放容器中的所有顶点(如果容器存储顶点对象而不是指针,则只需清除容器)