Skip to content

C++ 动态内存

动态内存是指在程序运行时分配和释放的内存。C++ 提供了newdelete运算符来管理动态内存。

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++ 动态内存包括:

  1. 动态内存的基本概念

    • 动态内存是在堆上分配的内存
    • 使用newdelete运算符管理动态内存
  2. 分配单个对象

    • 分配基本类型:new int
    • 分配自定义类型:new Student(...)
    • 释放内存:delete ptr
  3. 分配数组

    • 分配基本类型数组:new int[5]
    • 分配自定义类型数组:new Student[3]
    • 释放数组内存:delete[] arr
  4. 内存泄漏

    • 内存泄漏是指分配的内存没有被正确释放
    • 避免内存泄漏:确保每次new都有对应的delete
  5. 智能指针

    • std::unique_ptr:独占所有权的智能指针
    • std::shared_ptr:共享所有权的智能指针
    • std::weak_ptr:弱引用智能指针
  6. new 和 delete 的异常

    • new失败抛出std::bad_alloc异常
    • 使用std::nothrownew失败时返回nullptr

关键概念:

  • 动态内存:在程序运行时分配和释放的内存
  • :动态内存分配的区域
  • new:分配动态内存的运算符
  • delete:释放动态内存的运算符
  • 内存泄漏:分配的内存没有被正确释放
  • 智能指针:自动管理动态内存生命周期的指针
  • unique_ptr:独占所有权的智能指针
  • shared_ptr:共享所有权的智能指针
  • weak_ptr:弱引用智能指针

掌握动态内存是编写高效 C++ 程序的重要基础,在后续章节中,我们将学习 C++ 的命名空间。