深入理解 C++ 中的 delete
目录
基础概念
在 C++ 中,delete 是一个操作符,用于释放通过 new 操作符分配的动态内存。当使用 new 创建一个对象时,它会在堆上分配内存并返回一个指向该对象的指针。使用完对象后,需要使用 delete 来释放这块内存,以避免内存泄漏。
使用方法
删除单个对象
当通过 new 创建一个单个对象时,使用 delete 来释放其内存。例如:
#include <iostream>
class MyClass {
public:
MyClass() {
std::cout << "MyClass constructor" << std::endl;
}
~MyClass() {
std::cout << "MyClass destructor" << std::endl;
}
};
int main() {
MyClass* myObject = new MyClass();
// 使用 myObject
delete myObject; // 释放内存并调用析构函数
return 0;
}
在上述代码中,new MyClass() 在堆上创建一个 MyClass 对象,并返回一个指向它的指针 myObject。当使用 delete myObject 时,对象的析构函数会被调用,然后内存被释放。
删除对象数组
如果使用 new[] 创建了一个对象数组,那么需要使用 delete[] 来释放内存。例如:
#include <iostream>
class MyClass {
public:
MyClass() {
std::cout << "MyClass constructor" << std::endl;
}
~MyClass() {
std::cout << "MyClass destructor" << std::endl;
}
};
int main() {
MyClass* myArray = new MyClass[3];
// 使用 myArray
delete[] myArray; // 释放数组内存并为每个对象调用析构函数
return 0;
}
这里 new MyClass[3] 创建了一个包含 3 个 MyClass 对象的数组。delete[] myArray 会为数组中的每个对象调用析构函数,然后释放整个数组的内存。
常见实践
与 new 配对使用
delete 必须与 new 正确配对使用。如果 new 用于分配内存,那么对应的 delete 必须在不再需要该内存时被调用。例如:
#include <iostream>
void someFunction() {
int* number = new int;
*number = 42;
// 做一些其他操作
delete number; // 释放内存
}
int main() {
someFunction();
return 0;
}
在 someFunction 函数中,new int 分配了内存,最后 delete number 释放了该内存,确保不会发生内存泄漏。
处理继承关系中的对象删除
在处理继承关系时,当通过基类指针删除派生类对象时,基类的析构函数必须声明为虚函数。例如:
#include <iostream>
class Base {
public:
virtual ~Base() {
std::cout << "Base destructor" << std::endl;
}
};
class Derived : public Base {
public:
~Derived() {
std::cout << "Derived destructor" << std::endl;
}
};
int main() {
Base* basePtr = new Derived();
delete basePtr; // 正确调用派生类析构函数
return 0;
}
如果基类的析构函数不是虚函数,delete basePtr 只会调用基类的析构函数,而不会调用派生类的析构函数,可能导致资源泄漏。
最佳实践
智能指针的使用
现代 C++ 推荐使用智能指针(如 std::unique_ptr 和 std::shared_ptr)来管理动态内存,而不是直接使用 delete。智能指针会自动处理内存的释放,减少了手动调用 delete 时出错的可能性。例如:
#include <iostream>
#include <memory>
class MyClass {
public:
MyClass() {
std::cout << "MyClass constructor" << std::endl;
}
~MyClass() {
std::cout << "MyClass destructor" << std::endl;
}
};
int main() {
std::unique_ptr<MyClass> myObject = std::make_unique<MyClass>();
// 使用 myObject
// 离开作用域时,myObject 会自动释放内存
return 0;
}
std::unique_ptr 会在其作用域结束时自动调用 delete,无需手动干预。
确保正确的对象生命周期管理
在复杂的程序中,确保对象的创建和删除时机正确非常重要。可以使用资源获取即初始化(RAII)原则,将资源的生命周期与对象的生命周期绑定。例如,智能指针就是基于 RAII 原则实现的。
小结
delete 是 C++ 中释放动态内存的重要操作符。正确使用 delete 与 new 配对,特别是在处理对象数组和继承关系时,是避免内存泄漏的关键。然而,现代 C++ 更倾向于使用智能指针来管理动态内存,以提高代码的安全性和可维护性。通过理解 delete 的基础概念、使用方法、常见实践以及最佳实践,开发者可以更好地管理内存,编写更健壮的 C++ 代码。