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

时间:2016-03-30 22:53:23

标签: c++ polymorphism smart-pointers stdvector

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

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

  1. 是否有任何内存泄漏?
  2. 如果我不打电话给shapes.clear(),会不会有内存泄漏?
  3. 有没有更好的方法来使用智能指针和容器?
  4. 代码:

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

    谢谢:)

6 个答案:

答案 0 :(得分:6)

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

不,如果你不打电话给shapes.clear(),那么自std::vector的析构函数清理容器后就不会有内存泄漏。

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

但是,我可以为创建std::shared_ptr

提供改进

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

答案 1 :(得分:4)

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

2)什么都不会发生:如果你不做clear(),当剩下main()时,形状会被摧毁,导致它的竞争被摧毁。

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

答案 2 :(得分:3)

不,不存在内存泄漏,这是智能指针的整个部分(部分)。当vector超出范围时,它会在其所有元素上调用析构函数。在这种情况下,调用shared_ptr<Shape>上的析构函数将导致其内部共享引用计数命中0,从而破坏Shape对象。

答案 3 :(得分:3)

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

答案 4 :(得分:1)

  1. 没有
  2. 没有
  3. 也许。取决于您的需求。您所做的事情对于您粘贴的程序是合理的。

答案 5 :(得分:1)

  

是否有任何内存泄漏?

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

  

如果我没有调用shapes.clear(),会不会有内存泄漏?

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

  

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

如果make_shared通过确保new调用其析构函数来删除内存而引发异常,则可以使用

shared_ptr来避免问题。但是,这需要从shared_ptr<Rectangle>转换为shared_ptr<Shape>,如果烦人则会自动转换(包括复制shared_ptr并删除原始内容)。