C ++内存管理

news/2025/2/28 12:59:04/

1. 内存分区

在 C++ 里,内存主要分为以下几个区域:

  • 栈(Stack):由编译器自动分配和释放,用于存储局部变量、函数参数和返回地址等。其特点是内存分配和释放速度快,遵循后进先出(LIFO)原则。例如:

#include <iostream>void func() {int a = 10; // 变量 a 存储在栈上std::cout << a << std::endl;
}int main() {func();return 0;
}

  • 堆(Heap):由程序员手动管理,通过 new 和 delete(或 malloc 和 free)进行内存的分配和释放。堆的空间较大,但分配和释放的速度相对较慢,且容易出现内存泄漏问题。例如:

#include <iostream>int main() {int* ptr = new int(10); // 在堆上分配内存std::cout << *ptr << std::endl;delete ptr; // 释放堆上的内存return 0;
}

  • 全局 / 静态区(Global/Static Area):用于存储全局变量和静态变量。在程序启动时分配内存,程序结束时释放。例如:

#include <iostream>int globalVar = 20; // 全局变量,存储在全局/静态区void func() {static int staticVar = 30; // 静态变量,存储在全局/静态区std::cout << staticVar << std::endl;
}int main() {func();return 0;
}

  • 常量区(Constant Area):用于存储常量数据,如字符串常量。这些数据在程序运行期间不可修改。例如:

#include <iostream>int main() {const char* str = "Hello"; // 字符串常量存储在常量区std::cout << str << std::endl;return 0;
}

  • 代码区(Code Area):用于存储程序的可执行代码。

2. new 和 delete 与 malloc 和 free 的区别

  • 类型安全性new 和 delete 是 C++ 的运算符,具有类型安全性,会自动计算所需内存的大小,并返回正确类型的指针。而 malloc 和 free 是 C 语言的函数,返回 void* 类型的指针,需要手动进行类型转换。例如:

#include <iostream>int main() {int* ptr1 = new int(10); // new 自动处理类型int* ptr2 = (int*)malloc(sizeof(int)); // malloc 需要手动类型转换delete ptr1;free(ptr2);return 0;
}

  • 构造和析构new 在分配内存后会调用对象的构造函数进行初始化,delete 在释放内存前会调用对象的析构函数进行资源清理。而 malloc 和 free 只是单纯地分配和释放内存,不会调用构造和析构函数。例如:

#include <iostream>class MyClass {
public:MyClass() { std::cout << "Constructor" << std::endl; }~MyClass() { std::cout << "Destructor" << std::endl; }
};int main() {MyClass* obj1 = new MyClass(); // 调用构造函数delete obj1; // 调用析构函数MyClass* obj2 = (MyClass*)malloc(sizeof(MyClass)); // 不调用构造函数free(obj2); // 不调用析构函数return 0;
}

  • 异常处理new 在内存分配失败时会抛出 std::bad_alloc 异常,而 malloc 在内存分配失败时返回 NULL 指针。

3. 内存泄漏

内存泄漏指的是程序在动态分配内存后,由于某种原因未能正确释放这些内存,导致这部分内存无法被再次使用。常见的原因包括忘记调用 delete 或 free,或者在异常处理中没有正确释放内存。例如:

#include <iostream>void memoryLeak() {int* ptr = new int(10);// 忘记释放内存// delete ptr;
}int main() {memoryLeak();return 0;
}

为避免内存泄漏,可以使用智能指针(如 std::unique_ptrstd::shared_ptr 和 std::weak_ptr),它们会自动管理内存的生命周期。例如:

#include <iostream>
#include <memory>void noMemoryLeak() {std::unique_ptr<int> ptr = std::make_unique<int>(10);// 不需要手动释放内存,ptr 离开作用域时会自动释放
}int main() {noMemoryLeak();return 0;
}

4. 悬空指针

悬空指针是指指向已经被释放的内存的指针。使用悬空指针会导致未定义行为。例如:

#include <iostream>int main() {int* ptr = new int(10);delete ptr;// ptr 现在是悬空指针// *ptr = 20; // 未定义行为return 0;
}

为避免悬空指针问题,在释放内存后将指针置为 nullptr。例如:

#include <iostream>int main() {int* ptr = new int(10);delete ptr;ptr = nullptr; // 将指针置为 nullptrreturn 0;
}

5. 浅拷贝和深拷贝

  • 浅拷贝:浅拷贝只是简单地复制对象的成员变量的值,对于指针成员,只是复制指针的值,而不复制指针所指向的内存。这会导致多个对象共享同一块内存,当其中一个对象释放内存时,其他对象的指针就会成为悬空指针。例如:

收起

cpp

#include <iostream>class MyClass {
public:int* data;MyClass(int value) {data = new int(value);}// 浅拷贝构造函数MyClass(const MyClass& other) {data = other.data;}~MyClass() {delete data;}
};int main() {MyClass obj1(10);MyClass obj2(obj1); // 浅拷贝// 这里会出现问题,因为 obj1 和 obj2 共享同一块内存return 0;
}

  • 深拷贝:深拷贝会为新对象的指针成员分配新的内存,并将原对象指针所指向的内存内容复制到新的内存中。这样每个对象都有自己独立的内存副本,避免了悬空指针问题。例如:

收起

cpp

#include <iostream>class MyClass {
public:int* data;MyClass(int value) {data = new int(value);}// 深拷贝构造函数MyClass(const MyClass& other) {data = new int(*other.data);}~MyClass() {delete data;}
};int main() {MyClass obj1(10);MyClass obj2(obj1); // 深拷贝return 0;
}

6. 智能指针

智能指针是 C++ 标准库提供的模板类,用于自动管理动态分配的内存,避免手动管理内存带来的问题。常见的智能指针有:

  • std::unique_ptr:独占所有权的智能指针,同一时间只能有一个 std::unique_ptr 指向某个对象。例如:

收起

cpp

#include <iostream>
#include <memory>int main() {std::unique_ptr<int> ptr = std::make_unique<int>(10);// std::unique_ptr<int> ptr2 = ptr; // 错误,不能复制std::unique_ptr<int> ptr2 = std::move(ptr); // 可以转移所有权return 0;
}

  • std::shared_ptr:共享所有权的智能指针,多个 std::shared_ptr 可以指向同一个对象,使用引用计数来管理对象的生命周期,当引用计数为 0 时,对象会被自动释放。例如:

收起

cpp

#include <iostream>
#include <memory>int main() {std::shared_ptr<int> ptr1 = std::make_shared<int>(10);std::shared_ptr<int> ptr2 = ptr1; // 可以复制return 0;
}
  • std::weak_ptr:弱引用的智能指针,它不拥有对象的所有权,主要用于解决 std::shared_ptr 的循环引用问题。例如:
#include <iostream>
#include <memory>class B;class A {
public:std::shared_ptr<B> bPtr;~A() { std::cout << "A destructor" << std::endl; }
};class B {
public:std::weak_ptr<A> aPtr; // 使用 std::weak_ptr 避免循环引用~B() { std::cout << "B destructor" << std::endl; }
};int main() {std::shared_ptr<A> a = std::make_shared<A>();std::shared_ptr<B> b = std::make_shared<B>();a->bPtr = b;b->aPtr = a;return 0;
}

http://www.ppmy.cn/news/1575506.html

相关文章

C#快捷键的应用

Ctrl键下面的键 // z 撤回 ​ // x 剪切 ​ // c 复制 ​ // v 粘贴 ​ // a 全选 ​ // s 保存 ​ // f 搜索 ​ // h 替换 ​ // y 反撤销&#xff08;撤销过了&#xff09; ​ // 不选中…

利用DeepSeek-Kimi打通Excel与PPT的链条,自动生成数据分析报告

通过DeepSeek在Excel生成结构化的数据分析报告&#xff0c;再借助Kimi的PPT助手将报告自动转换为专业的PPT演示文稿&#xff0c;从而实现从数据到展示的一站式解决方案。 案例数据 1.一键生成数据分析报告 在下载并安装“Excel矩阵”后&#xff0c;我们启用DeepSeek的右侧对话…

HarmonyOS NEXT 原生应用/元服务调试概述

一、概述 DevEco Studio提供了丰富的HarmonyOS应用/元服务调试能力&#xff0c;支持JS、ArkTS、C/C单语言调试和ArkTS/JSC/C跨语言调试能力&#xff0c;并且支持三方库源码调试&#xff0c;帮助开发者更方便、高效地调试应用/元服务。 HarmonyOS应用/元服务调试支持使用真机设备…

SOME/IP-SD -- 协议英文原文讲解4

前言 SOME/IP协议越来越多的用于汽车电子行业中&#xff0c;关于协议详细完全的中文资料却没有&#xff0c;所以我将结合工作经验并对照英文原版协议做一系列的文章。基本分三大块&#xff1a; 1. SOME/IP协议讲解 2. SOME/IP-SD协议讲解 3. python/C举例调试讲解 5.1.2.4.5…

SkyTower: 1靶场渗透测试

SkyTower: 1靶场 来自 <SkyTower: 1 ~ VulnHub> 1&#xff0c;发现靶场不能够所以VMware打开&#xff0c;所以就所以VirtualBox打开&#xff0c;然后两个虚拟机都所以桥接模式使得能够互相通信 2&#xff0c;攻击机上做namp局域网扫描发现靶机 nmap -sn 192.168.1.0/24 …

浅谈Linux中的软件包管理器——基于ubuntu环境

文章目录 1. 为什么要使用软件包管理器1.1 使用源码1.2 使用rpm安装包1.3 使用apt软件包管理器 2. 如何使用apt2.1 软件的安装和卸载2.2 查找和搜素软件包2.3 更新并升级软件包2.4 清理缓存 3. 从apt到系统生态 1. 为什么要使用软件包管理器 在Linux中&#xff0c;有三种软件安…

嵌入式硬件篇---常用的汇编语言指令

文章目录 前言汇编语言简介1. 数据传送指令MOVPUSHPOPXCHG 2. 算术运算指令ADDSUBMULDIVINCDEC 3. 逻辑运算指令ANDORXORNOTSHL/SHR 4. 控制转移指令JMPCALLRETJE/JZJNE/JNZJG/JNLEJL/JNGE 5. 比较与测试指令CMPTEST 6. 标志寄存器操作指令STCCLCSTDCLD 7. 字符串操作指令MOVSL…

微信小程序调用火山方舟(字节跳动火山引擎)中的DeepSeek大模型

微信小程序的轻量化特性与DeepSeek大模型的AI能力结合&#xff0c;可快速构建智能问答、内容生成等场景化服务。通过火山方舟平台提供的标准化接口&#xff0c;开发者无需深入算法细节即可调用模型能力。 一、注册火山引擎账号&#xff0c;创建API Key和model&#xff08;接入…