我编写了经典的Shape Polymorphism代码,但有点不同,因为我使用的是Vector容器和智能指针。
我不是C ++专家,我想知道以下内容:
shapes.clear()
,会不会有内存泄漏?代码:
#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;
}
谢谢:)
答案 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)
std::shared_ptr
也会正确地破坏元素。 (无论如何你应该添加它 - 迟早有人会遇到这个问题,因为std::unique_ptr
将不会处理这种情况).clear()
也不会有任何内存泄漏 - std::vector
的析构函数会破坏所有元素,而共享指针会破坏所拥有的元素唯一的老板。std::unique_ptr
,但前提是Shape
中有虚拟析构函数。您还应该尽可能使用std::make_shared
和std::make_unique
(C ++ 14)来避免序列点和抛出构造函数的棘手问题:本质上f(std::unique_ptr<ConstructorAlwaysThrows>(new ConstructorAlwaysThrows()), std::unique_ptr<Foo>(new Foo()));
会泄漏内存,或者不会,取决于编译器的排序方式。答案 4 :(得分:1)
答案 5 :(得分:1)
是否有任何内存泄漏?
不,你在这里调用shared_ptr
的析构函数。
如果我没有调用shapes.clear(),会不会有内存泄漏?
这取决于,如果你的vector
存在,那么它的所有内容都将存在,如果vector
死亡,那么它将自动终止其内容。
如果有没有更好的方法来使用智能指针和容器?
make_shared
通过确保new
调用其析构函数来删除内存而引发异常,则可以使用 shared_ptr
来避免问题。但是,这需要从shared_ptr<Rectangle>
转换为shared_ptr<Shape>
,如果烦人则会自动转换(包括复制shared_ptr
并删除原始内容)。