繁体   English   中英

Vector容器中的C ++智能指针

[英]C++ Smart Pointers in a Vector container

我编写了经典的Shape Polymorphism代码,但有点不同,因为我使用的是Vector容器和智能指针。

我不是C ++专家,我想知道以下内容:

  1. 有内存泄漏吗?
  2. 如果我不调用shapes.clear() ,是否会出现内存泄漏?
  3. 有没有更好的方法来使用智能指针和容器?

码:

#include <iostream>
#include <memory>
#include <vector>
using namespace std;

class Shape {
  public:
    virtual float getArea() = 0;
    virtual ~Shape() {}
};

class Rectangle : public Shape {
  public:
    Rectangle(float w, float h) : width(w), height(h) {}

    float getArea() {
      return width * height;
    }
  private:
    float width;
    float height;
};

class Circle : public Shape {
  public:
    Circle(float r) : radius(r) {}

    float getArea() {
      return 3.141592653589793238462643383279502884 * radius * radius;
    }
  private:
    float radius;
};

void printShapeAreas(vector<shared_ptr<Shape>> &shapes) {
  for(int i = 0; i < shapes.size(); i++) {
    cout << shapes[i]->getArea() << endl;
  }
}

int main(int argc, char** argv) {
  vector<shared_ptr<Shape>> shapes;
  //this works, but you told me that is better to use make_shared
  //=============================================================
  //shapes.push_back(shared_ptr<Shape>(new Rectangle(10, 2)));
  //shapes.push_back(shared_ptr<Shape>(new Rectangle(10, 3)));
  //shapes.push_back(shared_ptr<Shape>(new Circle(2)));
  //shapes.push_back(shared_ptr<Shape>(new Circle(3)));
  //better
  //======
  shapes.push_back(std::make_shared<Rectangle>(10, 2));
  shapes.push_back(std::make_shared<Rectangle>(10, 3));
  shapes.push_back(std::make_shared<Circle>(2));
  shapes.push_back(std::make_shared<Circle>(3));
  printShapeAreas(shapes);
  shapes.clear();//If I don't call shapes.clear(), is there going to be a memory leak?
  return 0;
}

谢谢 :)

您的代码不包含内存泄漏。 所以你的第一点很好。

不,如果你不调用shapes.clear() ,就不会有内存泄漏,因为std::vector的析构函数会清理容器。

我不知道在容器中使用共享指针的具体规则,所以我将跳过你的第三个问题。

但是,我可以为创建std::shared_ptr提供改进:

使用其构造函数创建共享指针时,即shared_ptr<T>(new T()); 控制块或保存有关该资源的簿记信息的结构是与它指向的对象分开创建的。 这可能会导致缓存丢失很多。 但是,如果使用std::make_shared创建shared_ptr ,则控制块将分配您想要的对象,因此,通过将它们保持在一起,您至少可以降低缓存未命中的成本: std::make_shared<T>(); 例如: std::make_shared<Circle>(3)相当于编写std::shared_ptr<Shape>(new Circle(3)) ,但通常更好。

1)我在这里看不到内存泄漏。 然而,迟早有可能获得一个: 你的形状析构函数不是虚拟的 这意味着总是使用基础析构函数而不是正确的析构函数销毁形状。 也就是说,如果你的某个派生形状有一天会分配内存,那么它的析构函数将不会被调用。

2)什么都不会发生:如果你没有做一个clear() ,当main()离开时,形状会被破坏,导致它的竞争被破坏。

3)也许,但这个已经非常好了。

不,不存在内存泄漏,这是智能指针的整个点(部分)。 vector超出范围时,它会在其所有元素上调用析构函数。 在这种情况下,在shared_ptr<Shape>上调用析构函数将导致其内部共享引用计数达到0并因此将销毁Shape对象。

  1. 没有,不在您发布的代码中 - 即使没有虚拟析构函数, std::shared_ptr也会正确地破坏元素。 (无论如何你应该添加它 - 迟早有人会遇到这个问题,因为std::unique_ptr不会处理这种情况)
  2. 即使你不调用也不会有任何内存泄漏.clear() - std::vector的析构函数会破坏所有元素,如果共享指针是唯一的所有者,则共享指针会破坏所拥有的元素。
  3. 如果您不需要共享所有权,则可以使用std::unique_ptr ,但std::unique_ptr是您在Shape有虚拟析构函数。 您还应该使用std::make_sharedstd::make_unique (C ++ 14)来避免序列点和抛出构造函数的棘手问题:本质上f(std::unique_ptr<ConstructorAlwaysThrows>(new ConstructorAlwaysThrows()), std::unique_ptr<Foo>(new Foo())); 会不会泄漏内存,具体取决于编译器的排序方式。
  1. 没有。
  2. 没有。
  3. 也许。 取决于您的需求。 您所做的事情对于您粘贴的程序是合理的。

有内存泄漏吗?

不,你在这里调用shared_ptr的析构函数。

如果我不调用shapes.clear(),是否会出现内存泄漏?

这取决于,如果你的vector存在,那么它的所有内容都将存在,如果vector死亡,那么它将自动杀死它的内容。

有没有更好的方法来使用智能指针和容器?

如果new抛出异常, make_shared可用于避免问题,方法是确保shared_ptr调用其析构函数来删除内存。 但是,这需要从shared_ptr<Rectangle>转换为shared_ptr<Shape> ,如果烦人的话,它会自动转换(它涉及复制shared_ptr并删除原始内容)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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