Appearance
C++ 动态内存
动态内存是指在程序运行时分配和释放的内存。C++ 提供了new和delete运算符来管理动态内存。
1. 动态内存的基本概念
动态内存是在堆(heap)上分配的内存,它的大小可以在运行时确定,并且需要手动管理。
1.1 new 和 delete 运算符
cpp
#include <iostream>
int main() {
// 分配单个整数
int* ptr = new int;
*ptr = 10;
std::cout << "*ptr = " << *ptr << std::endl;
delete ptr;
// 分配整数数组
int* arr = new int[5];
for (int i = 0; i < 5; i++) {
arr[i] = i * 10;
}
for (int i = 0; i < 5; i++) {
std::cout << arr[i] << " ";
}
std::cout << std::endl;
delete[] arr;
return 0;
}2. 分配单个对象
2.1 基本类型
cpp
#include <iostream>
int main() {
int* ptr = new int;
*ptr = 10;
std::cout << "*ptr = " << *ptr << std::endl;
delete ptr;
return 0;
}2.2 自定义类型
cpp
#include <iostream>
class Student {
public:
std::string name;
int age;
Student(std::string name, int age) : name(name), age(age) {
std::cout << "构造函数被调用" << std::endl;
}
~Student() {
std::cout << "析构函数被调用" << std::endl;
}
void display() {
std::cout << "姓名: " << name << ", 年龄: " << age << std::endl;
}
};
int main() {
Student* student = new Student("张三", 20);
student->display();
delete student;
return 0;
}3. 分配数组
3.1 基本类型数组
cpp
#include <iostream>
int main() {
int* arr = new int[5];
for (int i = 0; i < 5; i++) {
arr[i] = i * 10;
}
for (int i = 0; i < 5; i++) {
std::cout << arr[i] << " ";
}
std::cout << std::endl;
delete[] arr;
return 0;
}3.2 自定义类型数组
cpp
#include <iostream>
class Student {
public:
std::string name;
int age;
Student(std::string name = "", int age = 0) : name(name), age(age) {
std::cout << "构造函数被调用" << std::endl;
}
~Student() {
std::cout << "析构函数被调用" << std::endl;
}
void display() {
std::cout << "姓名: " << name << ", 年龄: " << age << std::endl;
}
};
int main() {
Student* students = new Student[3];
students[0] = Student("张三", 20);
students[1] = Student("李四", 21);
students[2] = Student("王五", 22);
for (int i = 0; i < 3; i++) {
students[i].display();
}
delete[] students;
return 0;
}4. 内存泄漏
内存泄漏是指分配的内存没有被正确释放,导致内存无法被再次使用。
4.1 内存泄漏示例
cpp
#include <iostream>
void func() {
int* ptr = new int;
*ptr = 10;
// 忘记释放内存
}
int main() {
func();
return 0;
}4.2 避免内存泄漏
cpp
#include <iostream>
void func() {
int* ptr = new int;
*ptr = 10;
delete ptr;
}
int main() {
func();
return 0;
}5. 智能指针
智能指针是 C++11 引入的特性,它自动管理动态内存的生命周期。
5.1 std::unique_ptr
std::unique_ptr是独占所有权的智能指针,同一时间只能有一个std::unique_ptr指向对象。
cpp
#include <iostream>
#include <memory>
class Student {
public:
std::string name;
int age;
Student(std::string name, int age) : name(name), age(age) {
std::cout << "构造函数被调用" << std::endl;
}
~Student() {
std::cout << "析构函数被调用" << std::endl;
}
void display() {
std::cout << "姓名: " << name << ", 年龄: " << age << std::endl;
}
};
int main() {
std::unique_ptr<Student> student = std::make_unique<Student>("张三", 20);
student->display();
return 0;
}5.2 std::shared_ptr
std::shared_ptr是共享所有权的智能指针,多个std::shared_ptr可以指向同一个对象。
cpp
#include <iostream>
#include <memory>
class Student {
public:
std::string name;
int age;
Student(std::string name, int age) : name(name), age(age) {
std::cout << "构造函数被调用" << std::endl;
}
~Student() {
std::cout << "析构函数被调用" << std::endl;
}
void display() {
std::cout << "姓名: " << name << ", 年龄: " << age << std::endl;
}
};
int main() {
std::shared_ptr<Student> student1 = std::make_shared<Student>("张三", 20);
std::shared_ptr<Student> student2 = student1;
std::cout << "引用计数: " << student1.use_count() << std::endl;
student1->display();
student2->display();
return 0;
}5.3 std::weak_ptr
std::weak_ptr是弱引用智能指针,它不会增加引用计数。
cpp
#include <iostream>
#include <memory>
class Student;
class Course {
public:
std::string name;
std::weak_ptr<Student> student;
Course(std::string name) : name(name) {
std::cout << "课程构造函数被调用" << std::endl;
}
~Course() {
std::cout << "课程析构函数被调用" << std::endl;
}
};
class Student {
public:
std::string name;
std::shared_ptr<Course> course;
Student(std::string name) : name(name) {
std::cout << "学生构造函数被调用" << std::endl;
}
~Student() {
std::cout << "学生析构函数被调用" << std::endl;
}
};
int main() {
std::shared_ptr<Student> student = std::make_shared<Student>("张三");
std::shared_ptr<Course> course = std::make_shared<Course>("C++");
student->course = course;
course->student = student;
return 0;
}6. new 和 delete 的异常
6.1 new 失败抛出异常
cpp
#include <iostream>
#include <new>
int main() {
try {
int* ptr = new int[1000000000000];
delete[] ptr;
} catch (const std::bad_alloc& e) {
std::cout << "内存分配失败: " << e.what() << std::endl;
}
return 0;
}6.2 new 失败返回 nullptr
cpp
#include <iostream>
#include <new>
int main() {
int* ptr = new (std::nothrow) int[1000000000000];
if (ptr == nullptr) {
std::cout << "内存分配失败" << std::endl;
} else {
delete[] ptr;
}
return 0;
}7. 示例:综合运用
现在,让我们看一个综合运用各种动态内存特性的例子:
cpp
#include <iostream>
#include <memory>
#include <vector>
class Student {
public:
std::string name;
int age;
std::vector<double> grades;
Student(std::string name, int age) : name(name), age(age) {
std::cout << "学生 " << name << " 构造函数被调用" << std::endl;
}
~Student() {
std::cout << "学生 " << name << " 析构函数被调用" << std::endl;
}
void add_grade(double grade) {
grades.push_back(grade);
}
double get_average() {
if (grades.empty()) {
return 0.0;
}
double sum = 0;
for (double grade : grades) {
sum += grade;
}
return sum / grades.size();
}
void display() {
std::cout << "姓名: " << name << std::endl;
std::cout << "年龄: " << age << std::endl;
std::cout << "平均成绩: " << get_average() << std::endl;
}
};
class Classroom {
private:
std::vector<std::shared_ptr<Student>> students;
public:
void add_student(std::shared_ptr<Student> student) {
students.push_back(student);
}
void display_students() {
std::cout << "教室中的学生:" << std::endl;
for (const auto& student : students) {
student->display();
}
}
double get_class_average() {
if (students.empty()) {
return 0.0;
}
double sum = 0;
for (const auto& student : students) {
sum += student->get_average();
}
return sum / students.size();
}
};
int main() {
Classroom classroom;
std::shared_ptr<Student> student1 = std::make_shared<Student>("张三", 20);
student1->add_grade(90.0);
student1->add_grade(85.0);
student1->add_grade(95.0);
std::shared_ptr<Student> student2 = std::make_shared<Student>("李四", 21);
student2->add_grade(80.0);
student2->add_grade(75.0);
student2->add_grade(85.0);
std::shared_ptr<Student> student3 = std::make_shared<Student>("王五", 22);
student3->add_grade(95.0);
student3->add_grade(90.0);
student3->add_grade(100.0);
classroom.add_student(student1);
classroom.add_student(student2);
classroom.add_student(student3);
classroom.display_students();
std::cout << "班级平均成绩: " << classroom.get_class_average() << std::endl;
return 0;
}小结
C++ 动态内存包括:
动态内存的基本概念:
- 动态内存是在堆上分配的内存
- 使用
new和delete运算符管理动态内存
分配单个对象:
- 分配基本类型:
new int - 分配自定义类型:
new Student(...) - 释放内存:
delete ptr
- 分配基本类型:
分配数组:
- 分配基本类型数组:
new int[5] - 分配自定义类型数组:
new Student[3] - 释放数组内存:
delete[] arr
- 分配基本类型数组:
内存泄漏:
- 内存泄漏是指分配的内存没有被正确释放
- 避免内存泄漏:确保每次
new都有对应的delete
智能指针:
std::unique_ptr:独占所有权的智能指针std::shared_ptr:共享所有权的智能指针std::weak_ptr:弱引用智能指针
new 和 delete 的异常:
new失败抛出std::bad_alloc异常- 使用
std::nothrow让new失败时返回nullptr
关键概念:
- 动态内存:在程序运行时分配和释放的内存
- 堆:动态内存分配的区域
- new:分配动态内存的运算符
- delete:释放动态内存的运算符
- 内存泄漏:分配的内存没有被正确释放
- 智能指针:自动管理动态内存生命周期的指针
- unique_ptr:独占所有权的智能指针
- shared_ptr:共享所有权的智能指针
- weak_ptr:弱引用智能指针
掌握动态内存是编写高效 C++ 程序的重要基础,在后续章节中,我们将学习 C++ 的命名空间。