簡體   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