十四天学会C++之第九天:内存管理

news2024/12/23 5:04:27

1. new和delete运算符

  • new运算符:动态分配内存。
  • delete运算符:释放动态分配的内存。

new运算符:动态分配内存

new运算符的作用是在堆内存中动态分配内存块,并返回指向该内存块的指针。这使得我们能够在程序运行时创建变量,而不必在编译时知道其大小。

如何使用new来动态分配一个整数:

int* dynamicInt = new int;
*dynamicInt = 42; // 给动态分配的整数赋值

我们首先使用new分配了一个整数大小的内存块,然后通过指针dynamicInt来访问它。请注意,一定要记得在不再需要这块内存时使用delete来释放它,以免造成内存泄漏。

delete运算符:释放动态分配的内存

如何使用delete运算符来释放动态分配的内存。它的语法很简单,只需使用delete后跟要释放的指针即可:

delete dynamicInt; // 释放动态分配的整数内存

相当于告诉编译器我们不再需要这块内存,它可以被回收以供其他用途。请注意,如果忘记释放动态分配的内存,将会导致内存泄漏,这会严重影响程序性能。

动态内存管理的责任

在使用new和delete时,要格外小心。内存泄漏是一个常见的问题,可以通过良好的内存管理来避免。确保在不再需要动态分配的内存时及时释放它,以确保程序的稳定性和性能。

代码示例

#include <iostream>

int main() {
    // 使用new分配动态内存
    int* dynamicInt = new int;
    *dynamicInt = 42;

    // 使用delete释放内存
    delete dynamicInt;

    return 0;
}

演示如何使用new和delete运算符来分配和释放动态内存。记住,合理的内存管理是编程中不可或缺的一部分,可以帮助我们编写高效且稳定的程序。

2. 动态内存分配

  • 动态内存分配的概念和重要性。
  • 使用new动态分配内存。
  • 使用delete释放动态分配的内存。

动态内存分配的概念

与静态内存分配不同,动态内存分配发生在程序运行时,而不是在编译时。这意味着我们可以根据需要分配内存,而不必提前知道内存的大小或生命周期。

动态内存分配的重要性在于,它允许我们创建变量、数据结构和对象,这些可以根据程序的运行情况进行调整,从而更好地适应不同的应用场景。

使用new动态分配内存

在C++中,我们使用new运算符来执行动态内存分配。

int* dynamicInt = new int;
*dynamicInt = 42; // 给动态分配的整数赋值

我们使用new分配了一个整数大小的内存块,并将其地址存储在dynamicInt指针中。然后,可以通过指针来访问和操作这块内存。

使用delete释放动态分配的内存

与动态分配内存一样重要的是释放它,以防止内存泄漏。我们使用delete运算符来释放动态分配的内存。下面是释放前面动态分配的整数内存的代码:

delete dynamicInt; // 释放动态分配的整数内存

通过调用delete dynamicInt,我们告诉编译器不再需要这块内存,可以将其释放以供其他用途。这个步骤至关重要,因为不释放动态分配的内存会导致内存泄漏,严重影响程序性能和稳定性。

3. 指针和引用

  • 指针和引用的基本概念。
  • 如何使用指针和引用来管理动态分配的内存。

指针和引用的基本概念

指针是一个变量,它存储了另一个变量的地址。通过指针,可以直接访问和操作存储在该地址上的数据。

引用是一个别名,它允许我们通过不同的名称访问相同的变量。引用通常用于函数参数和返回值,以便避免复制大量数据。

使用指针管理动态内存

指针在动态内存管理中非常有用。通过指针,可以轻松地访问和修改动态分配的内存。

如何使用指针来管理动态分配的整数数组:

int* dynamicArray = new int[5]; // 动态分配整数数组
dynamicArray[0] = 1;
dynamicArray[1] = 2;
// ...
delete[] dynamicArray; // 释放动态分配的数组内存

首先使用new分配了一个包含5个整数的数组,并将其地址存储在dynamicArray指针中。然后,可以使用指针访问数组的元素,并最终使用delete[]释放内存。

使用引用管理动态内存

引用通常用于管理动态分配的内存时传递参数。如何在函数中使用引用来修改动态分配的整数:

void modifyDynamicInt(int& x) {
    x = 42;
}

int main() {
    int* dynamicInt = new int;
    modifyDynamicInt(*dynamicInt);
    // dynamicInt现在包含值42
    delete dynamicInt;
    return 0;
}

定义一个接受整数引用的函数modifyDynamicInt。通过在main函数中使用引用,可以直接修改动态分配的整数,而不必担心指针或复制数据。

4. 内存泄漏和释放

  • 内存泄漏的定义和原因。
  • 如何避免内存泄漏。
  • 显式释放内存的重要性。

内存泄漏的定义和原因

内存泄漏是指在程序运行期间未能释放不再需要的内存,导致内存资源的浪费。这可能会导致程序性能下降,甚至崩溃。

内存泄漏通常发生在以下情况下:

  1. 忘记释放动态分配的内存。
  2. 丢失对动态分配内存的指针,无法再释放它。
  3. 重复分配内存,丢失对之前分配内存的指针。

如何避免内存泄漏

为了避免内存泄漏,我们可以采取以下措施:

  1. 始终在使用完动态分配内存后记得使用deletedelete[]来释放它。例如:
int* dynamicInt = new int;
// 使用dynamicInt
delete dynamicInt; // 释放内存
  1. 使用智能指针(例如std::shared_ptrstd::unique_ptr),它们会自动管理内存释放,避免手动释放内存的麻烦。

显式释放内存的重要性

即使在现代C++中,智能指针等工具可以帮助我们更轻松地管理内存,但了解如何显式释放内存仍然是一个重要的技能。直接管理内存资源,或者与遗留代码交互,这时手动释放内存是必要的。

5. 示例和练习

示例 1:动态分配和释放内存
#include <iostream>

int main() {
    // 动态分配一个整数
    int* dynamicInt = new int;
    
    // 检查内存是否成功分配
    if (dynamicInt == nullptr) {
        std::cerr << "内存分配失败" << std::endl;
        return 1;
    }
    
    // 使用动态分配的整数
    *dynamicInt = 42;
    
    // 释放内存
    delete dynamicInt;
    
    return 0;
}
示例 2:使用智能指针
#include <iostream>
#include <memory>

int main() {
    // 使用std::unique_ptr自动管理内存释放
    std::unique_ptr<int> smartInt = std::make_unique<int>(42);
    
    // 不需要手动释放内存
    
    // 使用智能指针时,当超出作用域时内存会自动释放
    
    return 0;
}
练习题
动态分配字符数组并释放内存
#include <iostream>

int main() {
    // 动态分配一个字符数组
    int size = 10;
    char* dynamicArray = new char[size];
    
    // 检查内存是否成功分配
    if (dynamicArray == nullptr) {
        std::cerr << "内存分配失败" << std::endl;
        return 1;
    }
    
    // 使用动态分配的字符数组
    for (int i = 0; i < size; ++i) {
        dynamicArray[i] = 'A' + i;
    }
    
    // 打印字符数组内容
    for (int i = 0; i < size; ++i) {
        std::cout << dynamicArray[i] << " ";
    }
    std::cout << std::endl;
    
    // 释放内存
    delete[] dynamicArray;
    
    return 0;
}

运行结果:
在这里插入图片描述

动态分配了一个字符数组,使用循环填充了它,然后在程序结束时使用delete[]释放了内存。

示例 2:创建函数模板来计算和
#include <iostream>

// 创建一个函数模板,计算两个数的和
template <typename T>
T calculateSum(T a, T b) {
    return a + b;
}

int main() {
    // 使用函数模板计算整数和浮点数的和
    int intSum = calculateSum(5, 3);
    double doubleSum = calculateSum(2.5, 3.7);
    
    std::cout << "整数和: " << intSum << std::endl;
    std::cout << "浮点数和: " << doubleSum << std::endl;
    
    return 0;
}

运行结果:
在这里插入图片描述

我们定义一个函数模板calculateSum,它可以接受不同类型的参数,并返回它们的和。然后在main函数中使用该模板来计算整数和浮点数的和。

示例 3:创建一个通用的容器类模板
#include <iostream>
#include <vector>
#include <string>

// 创建一个通用的容器类模板
template <typename T>
class GenericContainer {
public:
    // 构造函数
    GenericContainer() {}

    // 添加元素到容器
    void add(const T& item) {
        container.push_back(item);
    }

    // 打印容器中的元素
    void print() {
        for (const T& item : container) {
            std::cout << item << " ";
        }
        std::cout << std::endl;
    }

private:
    std::vector<T> container;
};

int main() {
    // 使用容器类模板存储整数
    GenericContainer<int> intContainer;
    intContainer.add(5);
    intContainer.add(10);
    intContainer.add(15);

    // 使用容器类模板存储字符串
    GenericContainer<std::string> strContainer;
    strContainer.add("Hello");
    strContainer.add("World");

    // 打印整数容器
    std::cout << "整数容器中的元素: ";
    intContainer.print();

    // 打印字符串容器
    std::cout << "字符串容器中的元素: ";
    strContainer.print();

    return 0;
}

运行结果:

在这里插入图片描述

创建一个通用的容器类模板GenericContainer,它可以存储不同类型的数据。我们使用它来存储整数和字符串,并在main函数中打印它们的内容。

示例 4:动态分配整数数组并计算平均值
#include <iostream>

int main() {
    // 动态分配整数数组
    int size = 5;
    int* scores = new int[size];

    // 输入分数
    std::cout << "请输入 " << size << " 个分数:" << std::endl;
    for (int i = 0; i < size; ++i) {
        std::cin >> scores[i];
    }

    // 计算平均值
    int sum = 0;
    for (int i = 0; i < size; ++i) {
        sum += scores[i];
    }
    double average = static_cast<double>(sum) / size;

    std::cout << "平均值: " << average << std::endl;

    // 释放内存
    delete[] scores;

    return 0;
}

运行结果:

在这里插入图片描述

动态分配了一个整数数组,然后输入分数并计算它们的平均值,最后使用delete[]释放了内存。

示例 5:使用智能指针std::shared_ptr管理字符串
#include <iostream>
#include <memory>
#include <vector>

int main() {
    // 创建一个vector来存储shared_ptr
    std::vector<std::shared_ptr<std::string>> stringPtrs;

    // 添加字符串到vector
    stringPtrs.push_back(std::make_shared<std::string>("Hello"));
    stringPtrs.push_back(std::make_shared<std::string>("World"));

    // 打印字符串
    for (const auto& ptr : stringPtrs) {
        std::cout << *ptr << " ";
    }
    std::cout << std::endl;

    // 检查字符串是否被释放
    std::cout << "检查字符串是否被释放:" << std::endl;
    for (const auto& ptr : stringPtrs) {
        if (ptr.unique()) {
            std::cout << "字符串 \"" << *ptr << "\" 已被释放" << std::endl;
        } else {
            std::cout << "字符串 \"" << *ptr << "\" 仍然存在" << std::endl;
        }
    }

    return 0;
}

运行结果:

在这里插入图片描述

使用std::shared_ptr来管理一组字符串。添加两个字符串到stringPtrs vector,并在程序结束时检查字符串是否被释放。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1121145.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

短视频如何批量添加水印?实用技巧带你飞

在当今的数字时代&#xff0c;短视频已经成为一种非常流行的内容形式。无论是社交媒体还是视频分享网站&#xff0c;短视频都已经成为了一种非常有吸引力的内容。然而&#xff0c;对于一些拥有大量视频内容的创作者来说&#xff0c;添加水印可能是一项繁琐的任务。本文将介绍如…

沙箱对抗之反沙箱技巧

前言 我们经常会在红蓝对抗中遇到这种场景&#xff0c;离线免杀&#xff0c;但是10分钟又被杀&#xff0c;这就是云查杀的威力&#xff0c;而云查杀可以分为下列两种: 1.静态分析 2.动态分析 静态分析就是分析样本的结构&#xff0c;导入表&#xff0c;等等来判定是否是恶意程…

C语言实现顺序表(图解增删查改+代码)

文章目录 写在前面1. 顺序表的初始化和销毁1.1 顺序表的初始化(SLInit)1.2 顺序表的销毁(SLDestroy) 2. 插入数据2.1 尾插数据(SLPushBack)2.2 头插数据(SLPushFront)2.3 指定位置插入数据(SLInsert) 3. 删除数据3.1 尾删数据(SLPopBack)3.2 头删数据(SLPopFront)3.3 删除指定位…

DDR3笔记 频率配置

可参考 基于FPGA的DDR3设计&#xff08;2&#xff09;DDR3各时钟频率及带宽分析 - 知乎 (zhihu.com) DDR3的时钟频率配置要看两个手册&#xff1a; 1.DDR3器件的手册。 2.开发板芯片的手册 器件 器件名称&#xff1a;MT41J128M16JT-125:K tCK 1.25ns&#xff0c;就可以算出…

冒泡排序应用过程中遇到的问题

冒泡排序思想&#xff1a;相邻的两个数据两两比较&#xff0c;然后按顺序排出 代码展示1&#xff1a; #include<stdio.h>void sort(int arr1[],int sz) {for (int i 0; i < sz-1; i){for (int j i1; j < sz; j){if (arr1[i] > arr1[j]) {int temp 0;temp a…

Wordpress - Xydown独立下载页面插件

Wordpress - Xydown独立下载页面插件&#xff1b; 1.使用ftp将demo.php和download.php上传到网站根目录&#xff08;两个文件中设计网站信息的代码可根据实际情况修改为自己的信息&#xff09; 使用ftp将demo.php和download.php上传到网站根目录&#xff08;两个文件中设计…

消息服务MNS之初见

消息服务MNS 说到消息服务MNS&#xff0c;那么消息服务MNS是什么呢&#xff1f;为什么会有消息服务MNS这款产品的产生呢&#xff1f; 什么是消息服务MNS 消息服务-阿里云消息服务MNS&#xff08;Message Service&#xff09;是一种高效、可靠、安全、便捷和可弹性扩展的分布…

GB28181学习(十)——视音频文件下载

要求 SIP服务器接收到媒体接收者发送的视音频文件下载请求后向媒体流发送者发送媒体文件下载命令&#xff0c;媒体流发送者采用RTP将视频流传输给媒体流接收者&#xff0c;媒体流接收者直接将视频流保存为媒体文件&#xff1b;媒体流接收者或SIP服务器可通过配置查询等方式获取…

算法模板之双链表图文详解

文章目录 &#x1f4cb;前言一. ⛳️使用数组模拟双链表讲解1.1 &#x1f514;为什么我们要使用数组去模拟双链表&#xff1f;1.2 &#x1f514;用数组模拟实现双链表1.2.1 &#x1f47b;整体框架说明1.2.2 &#x1f47b;双链表查找和修改1.2.3 &#x1f47b;双链表插入结点1.2…

云数据仓库实践:AWS Redshift在大数据储存分析上的落地经验分享

&#x1f3c6;作者简介&#xff0c;黑夜开发者&#xff0c;CSDN领军人物&#xff0c;全栈领域优质创作者✌&#xff0c;CSDN博客专家&#xff0c;阿里云社区专家博主&#xff0c;2023年6月CSDN上海赛道top4。 &#x1f3c6;数年电商行业从业经验&#xff0c;历任核心研发工程师…

【RNA structures】RNA-seq 分析: RNA转录的重构和前沿测序技术

文章目录 RNA转录重建1 先简单介绍一下测序相关技术2 Map to Genome Methods2.1 Step1 Mapping reads to the genome2.2 Step2 Deal with spliced reads2.3 Step 3 Resolve individual transcripts and their expression levels 3 Align-de-novo approaches3.1 Step 1: Generat…

C语言------接续符和转义符

接续符和转义符--------- \ C语言中的\符号可以表示接续符和转义符。 C语言中的接续符( \ )放在一行代码的结尾&#xff0c;可以将下一行的内容提到这一行来。 \符号还有另一个作用 — 转义符。 C语言中的转义符()主要用于表示无回显字符&#xff0c;也可用于表示常规字符。 …

原型链继承

方式一&#xff1a;原型链继承 1.套路&#xff1a; &#xff08;1&#xff09;定义父类型构造函数 &#xff08;2&#xff09;给父类型的原型添加方法 &#xff08;3&#xff09;定义子类型的构造函数 &#xff08;4&#xff09;创建父类型的对象赋值给子类型的原型 &…

基于SpringBoot的家具商城管理系统

基于SpringBoot的家具商城管理系统的设计与实现【文末源码】 开发语言&#xff1a;Java数据库&#xff1a;MySQL技术&#xff1a;SpringBootMyBatisVue工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 系统展示 主页 家具详情 通知公告 登录界面 管理员界面 摘要 一段关于基于…

Windows下安装PyTorch(GPU版本)

PyTorch环境配置及安装 初步机器学习&#xff0c;这里记录下一些学习经过&#xff0c;之后以便于自己查看&#xff0c;同时欢迎各位大佬点评&#xff0c;本节是机器计算的一个包的安装和简单验证。 1.流程 确定自己的硬件信息-确定电脑有英伟达&#xff08;NVIDIA&#xff…

给视频批量添加背景图,轻松简单的操作方法

当我们需要给多个视频添加相同的背景图片时&#xff0c;一个一个地添加未免太过于繁琐和低效。幸运的是&#xff0c;我们可以使用固乔剪辑助手这款软件来实现批量添加背景图片的操作。下面就是详细的步骤指南。 首先&#xff0c;我们需要在浏览器搜索“固乔科技”&#xff0c;然…

面试官心声:个个都说会自动化,结果面试一问细节全露馅了

今年我们部门计划招聘几名自动化测试工程师&#xff0c;为此我进行了面试和培训&#xff0c;发现了一个让我感到担忧的趋势&#xff0c;许多候选人可以轻松地回答有关脚本编写、元素定位、框架API等问题。然而一问到实际项目&#xff0c;比如“如何从0开始搭建自动化体系”、“…

【C语言】用函数实现模块化程序设计

前言&#xff1a;如果把所有的程序代码都写在一个主函数(main函数)中&#xff0c;就会使主函数变得庞杂、头绪不清&#xff0c;使阅读和维护程序变得困难。此外&#xff0c;有时程序中要多次实现某一功能&#xff0c;如果重新编写实现此功能就会使得程序冗长、不精炼。 &#x…

day02_numpy_demo

Numpy Numpy的优势ndarray属性基本操作 ndarray.func() numpy.func()ndarray的运算&#xff1a;逻辑运算、统计运算、数组间运算合并、分割、IO操作、数据处理,不过这个一般使用的是pandas Numpy的优势 Numpy numerical数值化 python 数值计算的python库&#xff0c;用于快…

Node.js--》简易资金管理系统后台项目实战(后端)

今天开始使用 node vue3 ts搭建一个简易资金管理系统的前后端分离项目&#xff0c;因为前后端分离所以会分两个专栏分别讲解前端与后端的实现&#xff0c;后端项目文章讲解可参考&#xff1a;前端链接&#xff0c;我会在前后端的两类专栏的最后一篇文章中会将项目代码开源到我…