当前位置:首页 » 《关于电脑》 » 正文

「C++系列」动态内存

17 人参与  2024年09月28日 19:20  分类 : 《关于电脑》  评论

点击全文阅读


【人工智能教程】,前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。

点击跳转到网站:【人工智能教程】

文章目录

一、动态内存1. 使用`new`和`delete`①分配单个对象②分配对象数组 2. 注意事项3. 智能指针4.示例:使用`std::unique_ptr` 二、内存管理函数1. C语言风格的内存管理函数2. C++特有的内存管理操作符3. 智能指针 三、栈内存和堆内存1. 栈内存(Stack Memory)2. 堆内存(Heap Memory)3. 注意事项4. 结论 四、相关链接

一、动态内存

在C++中,动态内存管理是一个重要的概念,它允许程序在运行时根据需要分配和释放内存。这与静态内存分配(在编译时确定大小)和栈内存分配(在函数调用时自动分配和释放)不同。动态内存分配通常使用newdelete操作符(对于单个对象)或new[]delete[]操作符(对于对象数组)来完成。

1. 使用newdelete

①分配单个对象

int* ptr = new int; // 分配一个int类型的内存空间*ptr = 10; // 使用该内存空间delete ptr; // 释放内存ptr = nullptr; // 避免野指针

②分配对象数组

int* arr = new int[10]; // 分配一个包含10个int的数组for(int i = 0; i < 10; ++i) {    arr[i] = i; // 初始化数组}delete[] arr; // 释放数组内存arr = nullptr; // 避免野指针

2. 注意事项

内存泄漏:如果分配了内存但没有释放,那么这块内存就会一直占用,直到程序结束。这可能导致程序使用的内存不断增加,最终耗尽系统资源。

野指针:如果释放了内存但没有将指针设置为nullptr,那么这个指针就变成了野指针。尝试通过野指针访问内存是未定义行为,可能导致程序崩溃。

异常安全:在分配内存后,如果发生异常,那么可能会跳过释放内存的代码。使用智能指针(如std::unique_ptrstd::shared_ptr)可以自动管理内存,提高代码的异常安全性。

3. 智能指针

C++11及以后的版本引入了智能指针,它们可以自动管理内存,减少内存泄漏和野指针的风险。

std::unique_ptr:独占式拥有其所指对象,同一时间内只能有一个std::unique_ptr指向给定对象(通过禁止拷贝构造函数和拷贝赋值操作符,只提供移动语义)。

std::shared_ptr:允许多个std::shared_ptr实例共享同一个对象。当最后一个拥有该对象的std::shared_ptr被销毁时,对象也会被销毁。

std::weak_ptr:一种不拥有其所指对象的智能指针,主要用来解决std::shared_ptr之间循环引用的问题。

4.示例:使用std::unique_ptr

#include <memory>int main() {    std::unique_ptr<int> ptr(new int(10));    // 使用ptr...    // 当ptr离开作用域时,它指向的内存会自动被释放    return 0;}

使用智能指针可以大大简化动态内存的管理,减少错误,提高代码的安全性和可维护性。

二、内存管理函数

在C++中,内存管理主要通过几种方式实现,包括使用C语言风格的内存管理函数以及C++特有的操作符和智能指针。以下是C++中常见的内存管理函数和机制:

1. C语言风格的内存管理函数

这些函数在C++中仍然可以使用,因为它们被C++继承并兼容。

malloc:用于动态分配指定大小的内存块。分配的内存不会自动初始化,其内容是不确定的。如果分配成功,返回指向分配的内存的指针;如果失败,返回NULL。
int* ptr = (int*)malloc(sizeof(int));if (ptr != NULL) {    // 使用ptr    free(ptr);}
calloc:类似于malloc,但它会额外将分配的内存初始化为零。它接受两个参数:元素的数量和每个元素的大小。
int* arr = (int*)calloc(10, sizeof(int));if (arr != NULL) {    // 使用arr    free(arr);}
realloc:用于调整之前通过malloc或calloc分配的内存块的大小。如果调整成功,返回指向新内存块的指针(可能与原指针相同,也可能不同);如果失败,返回NULL,并且原内存块保持不变。
int* new_arr = (int*)realloc(arr, 20 * sizeof(int));if (new_arr != NULL) {    arr = new_arr;    // 使用arr}free(arr);
free:用于释放之前通过malloc、calloc或realloc分配的内存块。同一块内存只能被释放一次,多次释放会导致未定义行为。
free(ptr);

2. C++特有的内存管理操作符

C++引入了newdelete操作符来简化内存管理,并自动处理对象的构造和析构。

new:用于动态分配内存,并自动调用对象的构造函数(如果适用)。对于内置类型,它类似于malloc,但不需要类型转换。对于类类型,它还会调用构造函数。
int* ptr = new int;MyClass* obj = new MyClass;delete ptr;delete obj;
new[]:用于动态分配一个对象数组的内存,并自动调用数组中每个对象的构造函数(如果适用)。
int* arr = new int[10];MyClass* objs = new MyClass[5];delete[] arr;delete[] objs;
delete:用于释放之前通过new分配的内存块,并自动调用对象的析构函数(如果适用)。delete[]:用于释放之前通过new[]分配的内存块,并自动调用数组中每个对象的析构函数(如果适用)。

3. 智能指针

C++11及以后的版本引入了智能指针,如std::unique_ptrstd::shared_ptrstd::weak_ptr,它们可以自动管理内存,减少内存泄漏和野指针的风险。

std::unique_ptr:独占式拥有其所指对象,同一时间内只能有一个std::unique_ptr指向给定对象。std::shared_ptr:允许多个std::shared_ptr实例共享同一个对象。当最后一个拥有该对象的std::shared_ptr被销毁时,对象也会被销毁。std::weak_ptr:一种不拥有其所指对象的智能指针,主要用来解决std::shared_ptr之间循环引用的问题。

智能指针通过封装裸指针并提供自动内存管理功能,使得C++中的动态内存管理更加安全和方便。

三、栈内存和堆内存

在C++中,内存管理是一个核心概念,它涉及到如何分配、使用和释放程序运行时所需的内存。C++程序中的内存主要分为几个区域,其中栈内存(Stack Memory)和堆内存(Heap Memory)是最常见的两种。

1. 栈内存(Stack Memory)

栈内存是自动分配和释放的内存区域。它遵循后进先出(LIFO, Last In First Out)的原则。栈内存主要用于存储局部变量、函数参数和返回值等。每当函数被调用时,它的局部变量和参数就会被推入栈中,并在函数返回时从栈中弹出。栈的大小在程序编译时就已经确定,并且通常比堆小得多。

特点

自动管理:不需要程序员手动分配和释放内存。速度快:由于栈内存的操作简单且高效,访问速度非常快。有限大小:栈的大小在编译时确定,并且相对较小,可能导致栈溢出(Stack Overflow)错误。

2. 堆内存(Heap Memory)

堆内存是动态分配和释放的内存区域。与栈内存不同,堆内存的大小不是固定的,它可以在程序运行时根据需要动态地增长和缩小。堆内存主要用于存储那些大小在程序编译时未知的对象,或者需要在程序的不同部分之间共享的数据。堆内存的分配和释放需要程序员手动管理,通常使用newdelete操作符(对于单个对象)或new[]delete[]操作符(对于对象数组)来完成。

特点

手动管理:程序员需要负责分配和释放内存,这增加了内存泄漏和野指针的风险。灵活:堆内存的大小可以在运行时动态变化,适合存储大小未知或变化的数据。相对较慢:与栈内存相比,堆内存的分配和释放操作更复杂,因此访问速度相对较慢。

3. 注意事项

内存泄漏:在堆上分配的内存如果没有被正确释放,就会导致内存泄漏。随着时间的推移,这可能会耗尽系统的可用内存。野指针:如果释放了堆上的内存但没有将指针设置为nullptr,那么这个指针就变成了野指针。尝试通过野指针访问内存是未定义行为,可能导致程序崩溃。栈溢出:如果栈上的局部变量太多或太大,就可能导致栈溢出错误。这通常发生在递归调用过深或局部变量占用大量内存时。

4. 结论

栈内存和堆内存各有优缺点,适用于不同的场景。栈内存适合存储局部变量和函数参数等小量数据,而堆内存则适合存储大量或动态变化的数据。在使用堆内存时,程序员需要格外注意内存的管理,以避免内存泄漏和野指针等问题。

在这里插入图片描述

四、相关链接

Visual Studio Code下载地址Sublime Text下载地址「C++系列」C++简介、应用领域「C++系列」C++ 基本语法「C++系列」C++ 数据类型「C++系列」C++ 变量类型「C++系列」C++ 变量作用域「C++系列」C++ 常量知识点-细致讲解「C++系列」C++ 修饰符类型「C++系列」一篇文章说透【存储类】「C++系列」一篇文章讲透【运算符】「C++系列」循环「C++系列」判断「C++系列」函数/内置函数「C++系列」数字/随机数「C++系列」数组「C++系列」字符串「C++系列」指针「C++系列」引用「C++系列」日期/时间「C++系列」输入/输出「C++系列」数据结构「C++系列」vector 容器「C++系列」类/对象「C++系列」继承「C++系列」重载运算符/重载函数「C++系列」多态「C++系列」数据抽象「C++系列」数据封装「C++系列」 接口(抽象类)「C++系列」文件和流「C++系列」异常处理

点击全文阅读


本文链接:http://zhangshiyu.com/post/165962.html

<< 上一篇 下一篇 >>

  • 评论(0)
  • 赞助本站

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

关于我们 | 我要投稿 | 免责申明

Copyright © 2020-2022 ZhangShiYu.com Rights Reserved.豫ICP备2022013469号-1