简体   繁体   English

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

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

I wrote the classic Shape Polymorphism code, but a little bit different because I'm using a Vector container and smart pointers. 我编写了经典的Shape Polymorphism代码,但有点不同,因为我使用的是Vector容器和智能指针。

I am not a C++ expert, and I would like to know the following: 我不是C ++专家,我想知道以下内容:

  1. Is there any memory leak? 有内存泄漏吗?
  2. If I don't call shapes.clear() , is there going to be a memory leak? 如果我不调用shapes.clear() ,是否会出现内存泄漏?
  3. Is there a better way to use smart pointers and containers? 有没有更好的方法来使用智能指针和容器?

Code: 码:

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

Thank you :) 谢谢 :)

Your code doesn't contain a memory leak. 您的代码不包含内存泄漏。 So your first point is fine. 所以你的第一点很好。

No, if you don't call shapes.clear() , there will not be a memory leak since std::vector 's destructor cleans up the container. 不,如果你不调用shapes.clear() ,就不会有内存泄漏,因为std::vector的析构函数会清理容器。

I don't know a specific rule about using shared pointers in a container so I'll skip on your third question. 我不知道在容器中使用共享指针的具体规则,所以我将跳过你的第三个问题。

However, I can offer an improvement for creating std::shared_ptr s: 但是,我可以为创建std::shared_ptr提供改进:

When you create a shared pointer using its constructor, ie shared_ptr<T>(new T()); 使用其构造函数创建共享指针时,即shared_ptr<T>(new T()); , the control block or the structure that holds bookkeeping information about that resource, is created separately from the object it points to. 控制块或保存有关该资源的簿记信息的结构是与它指向的对象分开创建的。 This might cause cache misses a lot. 这可能会导致缓存丢失很多。 However, if you create a shared_ptr by using std::make_shared , the control block is allocated with the object you want, therefore, by keeping them together, you can at least mitigate the cost of cache misses: std::make_shared<T>(); 但是,如果使用std::make_shared创建shared_ptr ,则控制块将分配您想要的对象,因此,通过将它们保持在一起,您至少可以降低缓存未命中的成本: std::make_shared<T>(); . For example: std::make_shared<Circle>(3) is equivalent to writing std::shared_ptr<Shape>(new Circle(3)) , but usually better. 例如: std::make_shared<Circle>(3)相当于编写std::shared_ptr<Shape>(new Circle(3)) ,但通常更好。

1) I don't see a memory leak here. 1)我在这里看不到内存泄漏。 However there is a potential to getting one sooner or later: your shape destructor is not virtual . 然而,迟早有可能获得一个: 你的形状析构函数不是虚拟的 This means that shapes are always destroyed using the base destructor, instead of the right destructor. 这意味着总是使用基础析构函数而不是正确的析构函数销毁形状。 Ie if one of your derived shapes would one day allocate memory, it's destructor that would have to release it wouldn't be called. 也就是说,如果你的某个派生形状有一天会分配内存,那么它的析构函数将不会被调用。

2) Nothing will happen: if you don't do a clear() , shapes will get destroyed anyway when main() is left, causing its contend to get destroyed. 2)什么都不会发生:如果你没有做一个clear() ,当main()离开时,形状会被破坏,导致它的竞争被破坏。

3) Maybe, but this one is already very good. 3)也许,但这个已经非常好了。

No, there won't be a memory leak, which is (part of) the entire point of smart pointers. 不,不存在内存泄漏,这是智能指针的整个点(部分)。 When the vector falls out of scope, it calls the destructor on all of its elements. vector超出范围时,它会在其所有元素上调用析构函数。 In this case, calling the destructor on the shared_ptr<Shape> will cause it's internal shared reference count to hit 0 and will thus destroy the Shape object. 在这种情况下,在shared_ptr<Shape>上调用析构函数将导致其内部共享引用计数达到0并因此将销毁Shape对象。

  1. There isn't, not in the code you posted - even without virtual destructor, std::shared_ptr destroys the elements properly. 没有,不在您发布的代码中 - 即使没有虚拟析构函数, std::shared_ptr也会正确地破坏元素。 (you should add it anyway though - sooner or later someone will hit this issue, as std::unique_ptr won't handle this case) (无论如何你应该添加它 - 迟早有人会遇到这个问题,因为std::unique_ptr不会处理这种情况)
  2. There won't be any memory leak, even if you don't call .clear() - the destructor of std::vector destroys all the elements, and the shared pointers destroys the element owned if they're the only owner. 即使你不调用也不会有任何内存泄漏.clear() - std::vector的析构函数会破坏所有元素,如果共享指针是唯一的所有者,则共享指针会破坏所拥有的元素。
  3. If you don't need shared ownership, you can use std::unique_ptr instead, but only if you have a virtual destructor in Shape . 如果您不需要共享所有权,则可以使用std::unique_ptr ,但std::unique_ptr是您在Shape有虚拟析构函数。 You should also use std::make_shared and std::make_unique (C++14) wherever you can to avoid a tricky issue with sequence points and throwing constructors: in essence f(std::unique_ptr<ConstructorAlwaysThrows>(new ConstructorAlwaysThrows()), std::unique_ptr<Foo>(new Foo())); 您还应该使用std::make_sharedstd::make_unique (C ++ 14)来避免序列点和抛出构造函数的棘手问题:本质上f(std::unique_ptr<ConstructorAlwaysThrows>(new ConstructorAlwaysThrows()), std::unique_ptr<Foo>(new Foo())); will leak memory, or not, depending on how the compiler does sequencing. 会不会泄漏内存,具体取决于编译器的排序方式。
  1. No. 没有。
  2. No. 没有。
  3. Maybe. 也许。 Depends on your needs. 取决于您的需求。 What you've done is reasonable for the program you pasted. 您所做的事情对于您粘贴的程序是合理的。

Is there any memory leak? 有内存泄漏吗?

No, you are calling the destructor of shared_ptr here. 不,你在这里调用shared_ptr的析构函数。

If I don't call shapes.clear(), is there going to be a memory leak? 如果我不调用shapes.clear(),是否会出现内存泄漏?

It depends, if your vector lives then all of its contents will live, if the vector dies then it will kill its contents automatically. 这取决于,如果你的vector存在,那么它的所有内容都将存在,如果vector死亡,那么它将自动杀死它的内容。

Is there a better way to use smart pointers and containers? 有没有更好的方法来使用智能指针和容器?

make_shared can be used to avoid problems if the new throws an exception by ensuring that the shared_ptr calls its destructor to delete the memory. 如果new抛出异常, make_shared可用于避免问题,方法是确保shared_ptr调用其析构函数来删除内存。 However that would require a conversion from shared_ptr<Rectangle> to shared_ptr<Shape> which is automatic if annoying (it involves copying the shared_ptr and deleting the original). 但是,这需要从shared_ptr<Rectangle>转换为shared_ptr<Shape> ,如果烦人的话,它会自动转换(它涉及复制shared_ptr并删除原始内容)。

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

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