C++ 允许我们在运行时动态地分配内存。这被称为动态内存分配。
在其他编程语言(如 Java 和 Python)中,编译器会自动管理分配给变量的内存。但在 C++ 中并非如此。
在 C++ 中,我们需要在不再使用变量后手动释放动态分配的内存。
我们可以分别使用 new
和 delete
运算符来动态分配和释放内存。
C++ new 表达式
我们可以使用 new
表达式在运行时分配内存。例如:
// declare an int pointer
int* point_var;
// dynamically allocate memory
// using the new keyword
point_var = new int;
// assign value to allocated memory
*point_var = 45;
在这里,我们使用 new
表达式为 int
变量动态分配了内存。
请注意,我们使用了指针 point_var 来动态分配内存。这是因为 new
表达式返回的是内存位置的地址。
我们也可以在同一步骤中分配内存并初始化值:
// dynamically allocate memory
// and assign value
int* point_var = new int{45};
使用此语法可以避免未初始化的指针。未初始化的指针在解引用时可能会导致未定义的行为。因此,这是首选语法。
使用 new
表达式的语法是:
data_type* pointer_variable = new data_type{value};
delete 表达式
一旦我们不再需要使用动态声明的变量,我们就可以释放该变量占用的内存。
为此,我们可以使用 delete
表达式。它将内存返回给操作系统。这被称为内存释放。
delete
表达式的语法是:
delete pointer_variable;
让我们看一个例子。
// dynamically allocate memory
// and assign int variable
int* point_var = new int{45};
// print the value stored in memory
cout << *point_var; // Output: 45
// deallocate the memory
delete point_var;
// set pointer to nullptr
point_var = nullptr;
在这里,我们使用指针 point_var 为 int
变量动态分配了内存。
在打印 point_var 的内容后,我们使用 delete
释放了内存。
将指针在释放内存后设置为 nullptr
是一个好习惯,以避免在解引用指针时发生未定义的行为。
注意:不正确地释放内存可能导致内存泄漏,进而导致程序消耗大量内存。正确使用 delete
表达式对于防止内存泄漏和确保高效的内存管理至关重要。
示例 1:C++ 动态内存分配
#include <iostream>
using namespace std;
int main() {
// dynamically allocate memory
int* point_int = new int{45};
float* point_float = new float{45.45f};
cout << *point_int << endl;
cout << *point_float << endl;
// deallocate the memory
// set pointers to nullptr
delete point_int;
delete point_float;
return 0;
}
输出
45 45.45
在此程序中,我们为两个 int
和 float
类型的变量动态分配了内存。
在为它们分配值并打印它们之后,我们最终使用 delete
表达式释放了内存。
注意:动态内存分配可以使内存管理更有效率,特别是对于数组,通常我们直到运行时才知道数组的大小。
示例 2:C++ 数组的 new 和 delete 表达式
// C++ program to store GPA of n number of students and display it
// where n is the number of students entered by the user
#include <iostream>
using namespace std;
int main() {
int num;
cout << "Enter total number of students: ";
cin >> num;
float* ptr;
// memory allocation of num number of floats
ptr = new float[num];
cout << "Enter GPA of students." << endl;
for (int i = 0; i < num; ++i) {
cout << "Student" << i + 1 << ": ";
cin >> *(ptr + i);
}
cout << "\nDisplaying GPA of students." << endl;
for (int i = 0; i < num; ++i) {
cout << "Student" << i + 1 << ": " << *(ptr + i) << endl;
}
// ptr memory is released
delete[] ptr;
ptr = nullptr;
return 0;
}
输出
Enter total number of students: 4 Enter GPA of students. Student1: 3.6 Student2: 3.1 Student3: 3.9 Student4: 2.9 Displaying GPA of students. Student1: 3.6 Student2: 3.1 Student3: 3.9 Student4: 2.9
在此程序中,我们要求用户输入学生数量并将其存储在 num 变量中。
然后,我们使用 new 为 float
数组动态分配了内存。
我们使用指针表示法向数组输入数据(然后打印它们)。
当我们不再需要该数组时,我们使用以下代码释放了数组内存:
delete[] ptr;.
请注意 delete
后面的 []
。我们使用方括号 []
来表示内存释放的是数组。
示例 3:C++ 对象的 new 和 delete 表达式
#include <iostream>
using namespace std;
class Student {
private:
int age;
public:
// constructor initializes age to 12
Student() : age(12) {}
void get_age() {
cout << "Age = " << age << endl;
}
};
int main() {
// dynamically declare student object
Student* ptr = new Student();
// call get_age() function
ptr->get_age();
// ptr memory is released
delete ptr;
return 0;
}
输出
Age = 12
在此程序中,我们创建了一个 Student
类,该类有一个私有变量 age。
我们在 默认构造函数 Student()
中将 age 初始化为 12
,并通过 get_age()
函数打印其值。
在 main()
函数中,我们使用 new
表达式创建了一个 Student
对象,并使用指针 ptr 指向其地址。
对象创建的那一刻,Student()
构造函数会将 age 初始化为 12
。
然后,我们使用以下代码调用 get_age()
函数:
ptr->get_age();
请注意箭头运算符 ->
。此运算符用于使用指针访问类成员。
为什么要使用动态内存分配?
动态内存分配具有许多优点,例如:
- 灵活性:动态内存分配允许我们在运行时按需分配内存。当数据结构的大小在编译时未知或在程序执行期间发生变化时,这种灵活性非常有用。
- 数据结构:链表、树、图和可调整大小的数组(C++ 中的向量)等数据结构通常需要动态分配内存,以适应可变数量的数据。
- 资源管理:我们可以在需要时分配内存,在不再需要时释放内存。这有助于更好地利用资源。
- 动态数组:在 C++ 等语言中,静态数组的大小在编译时固定。动态内存分配允许我们创建大小在运行时确定的数组。
阅读更多