- 析构函数调用顺序:
- 当释放Shape指针数组时,对于数组中的每个指针,会先调用对应对象的析构函数。由于Shape类有虚析构函数,所以会根据对象的实际类型来调用析构函数。
- 例如,如果指针指向Circle对象,会先调用Circle类的析构函数,然后调用Shape类的析构函数。如果指针指向Rectangle对象,会先调用Rectangle类的析构函数,然后调用Shape类的析构函数。这是因为C++的析构顺序是从子类到基类。
- 利用Valgrind定位内存泄漏问题:
- 安装Valgrind:在Linux系统上,可以使用包管理器(如apt - get install valgrind)安装Valgrind。
- 运行程序:使用Valgrind运行包含内存泄漏的C++程序,例如
valgrind --leak - check = full./your_program
。
- 分析报告:Valgrind会生成详细的报告,指出内存泄漏发生的位置。报告中会包含泄漏内存块的大小、分配内存的函数调用栈等信息。通过分析调用栈,可以找到代码中分配内存但未释放的具体位置。
- 修改代码解决内存泄漏问题:
- 确保正确释放资源:检查对象的析构函数,确保所有在构造函数或其他成员函数中分配的动态内存(如使用
new
分配的内存)在析构函数中使用delete
(或delete[]
对于数组)正确释放。例如,如果Circle类有一个动态分配的成员变量int* radiusPtr
,在Circle的析构函数中应该有delete radiusPtr;
。
- 智能指针的使用:可以将Shape指针数组中的指针替换为智能指针(如
std::unique_ptr<Shape>
或std::shared_ptr<Shape>
)。智能指针会自动管理对象的生命周期,在对象不再需要时自动调用析构函数,从而避免手动管理内存带来的泄漏风险。例如:
#include <memory>
#include <vector>
class Shape {
public:
virtual ~Shape() = default;
};
class Circle : public Shape {
private:
int radius;
public:
Circle(int r) : radius(r) {}
};
class Rectangle : public Shape {
private:
int width;
int height;
public:
Rectangle(int w, int h) : width(w), height(h) {}
};
int main() {
std::vector<std::unique_ptr<Shape>> shapes;
shapes.emplace_back(std::make_unique<Circle>(5));
shapes.emplace_back(std::make_unique<Rectangle>(4, 6));
// 这里智能指针会自动管理对象的析构,无需手动释放
return 0;
}