我在使用类之间共享的指针的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++中进行编码。仅包含两个Vertexdouble对象(例如您的情况下的X和Y分量)最好存储在堆栈中,而无需指针间接寻址。因此,我将像这样声明Square类:

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

如果要代替某种形式的引用机制来嵌入Vertex对象,则可以将顶点存储在std::vector<Vertex>数组中,并在Square类中存储指向数组顶点位置的整数索引。

如果您确实希望与指针共享所有权语义,那么可以考虑使用智能指针,例如std::shared_ptr。没有明确的delete:引用计数达到零时,shared_ptr将自动释放内存。

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

Square类的构造函数中,您可以按值获取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创建智能指针。

10-02 04:19
查看更多