当前位置: 首页 > news >正文

C++(new和malloc)

目录

C++中内存区域划分:

malloc:

示例:

realloc:

new:

示例:

利用new开辟数组:

对malloc开辟的内存块进行一个初始化:


C++中内存区域划分:

栈内存:自动管理局部变量和函数调用帧,生命周期与其作用域绑定。如果递归过深可能会导致栈溢出。

堆内存:手动进行管理,通过new/malloc手动进行分配,容量受到系统限制,通过delete/free进行释放,否则会导致内存泄漏。

静态存储区:存放全局/静态变量,生命周期持续到程序结束。

常量区:存储字符串字面量和编译期常量,只读。

malloc:

用于在堆区上动态分配指定字节数的连续内存块,返回未初始化的void*指针,需要手动进行类型转换和释放。

需要注意:使用malloc分配内存时,需要判断是否分配成功,如果分配失败返回值未nullptr。需要手动初始化,如果未手动初始化可能含随机值。使用了malloc必须与free配对使用,进行内存释放,不然会导致内存泄漏。

示例:

#include <iostream>
#include <string>
#include <thread>class A {
public:A():_target(0){std::cout << "A::无参构造" << std::endl;}A(int target):_target(target){std::cout << "A::有参构造" << std::endl;}~A(){}void Get() {std::cout << "_target " << _target << std::endl;}
private:int _target;int* _data;
};int main() {A* ptr = (A*)malloc(sizeof(A));if (ptr == nullptr) {throw "error";}ptr->Get();free(ptr);return 0;
}

运行结果:

可以看出,malloc仅分配原始内存空间,不会调用类的构造函数,导致成员变量未被初始化,而直接调用成员函数Get()进行访问成员变量,会导致未定义行为。

#include <iostream>
#include <string>
#include <thread>class A {
public:A():_target(0),_data(new int(0)){std::cout << "A::无参构造" << std::endl;}A(int target,int data):_target(target),_data(new int(data)){std::cout << "A::有参构造" << std::endl;}~A(){delete _data;}void Get() {std::cout << "_target " << _target << std::endl;}
private:int _target;int* _data;
};int main() {int* ptr = (int*)malloc(10 * sizeof(int));if (ptr == nullptr) {throw "error";}for (int i = 0; i < 10; i++) {*(ptr + i) = i;}for (int i = 0; i < 10; i++) {std::cout << *(ptr + i) << " ";}free(ptr);return 0;
}

运行结果:

realloc:

调整已分配的内存块的大小,如果进行扩展的话,原内存块后方有足够空间,直接扩展并返回原指针,反之,如果内存块后方没有足够的空间,徐重新分配新内存块并复制数据,释放原内存块。

realloc失败也是返回nullptr,需要对其进行判断是否成功,如果当分配的内存大小为0则等效于free。尽量使用一个临时变量接收返回值,这样能够避免原指针被覆盖而导致的内存泄漏。

#include <iostream>
#include <string>
#include <thread>class A {
public:A():_target(0),_data(new int(0)){std::cout << "A::无参构造" << std::endl;}A(int target,int data):_target(target),_data(new int(data)){std::cout << "A::有参构造" << std::endl;}~A(){delete _data;}void Get() {std::cout << "_target " << _target << std::endl;}
private:int _target;int* _data;
};int main() {int* ptr = (int*)malloc(10 * sizeof(int));if (ptr == nullptr) {throw "error";}for (int i = 0; i < 10; i++) {*(ptr + i) = i;}for (int i = 0; i < 10; i++) {std::cout << *(ptr + i) << " ";}int* newptr = (int*)realloc(ptr,16*sizeof(int));if (newptr == nullptr) {free(ptr);return -1;}ptr = newptr;for (int i = 10; i < 16; i++) {*(ptr + i) = i;}for (int i = 0; i < 16; i++) {std::cout << *(ptr + i) << " ";}free(ptr);return 0;
}

运行结果:

使用realloc进行内存扩展,使用临时变量newptr进行接收其返回值,如果返回值为nullptr,则使用原指针ptr对原内存进行释放,避免了返回值将ptr进行覆盖而导致无法释放原内存块。如果扩展成功,那么将临时变量的值赋值给ptr,最后释放释放ptr就行或者newptr,因为这里是将newptr赋值给ptr,如果对ptr和newptr进行释放,则会导致双重释放。

new:

C++提供的更高层次的内存管理操作符,不只是会分配内存还可以进行初始化,提供类型安全。

示例:

#include <iostream>
#include <cstdlib>class A {
public:A():_target(0),_data(new int(0)){std::cout << "A::无参构造" << std::endl;}A(int target,int data):_target(target),_data(new int(data)){std::cout << "A::有参构造" << std::endl;}~A(){delete _data;std::cout << "A::析构函数" << std::endl;}void Get() {std::cout << "_target " << _target << std::endl;}
private:int _target;int* _data;
};int main() {A* ptr = new A();A* ptr1 = new A(10, 10);ptr->Get();ptr1->Get();delete ptr;delete ptr1;return 0;
}

运行结果:

从运行结果可以知道new进行初始化时,会调用构造函数,而当对其释放时,就会调用析构函数。如果通过显示调用了析构函数,还对其进行一个delete释放,那么则会导致双重释放,因为调用析构函数就会析构成员变量_data,而再对ptr进行释放时,尝试对整个对象进行释放,就会导致_data被释放分两次。

利用new开辟数组:

#include <iostream>
#include <cstdlib>class A {
public:A():_target(0),_data(new int(0)){std::cout << "A::无参构造" << std::endl;}A(int target,int data):_target(target),_data(new int(data)){std::cout << "A::有参构造" << std::endl;}~A(){delete _data;std::cout<<"A::析构函数"<<std::endl;}void Get() {std::cout << "_target " << _target << std::endl;}
private:int _target;int* _data;
};int main() {A* ptr = new A[3]{{1,1},{10,10},{6,6}};for (int i = 0; i < 3; i++) {(ptr + i)->Get();}delete[] ptr;return 0;
}

运行结果:

对malloc开辟的内存块进行一个初始化:

#include <iostream>
#include <cstdlib>class A {
public:A():_target(0),_data(new int(0)){std::cout << "A::无参构造" << std::endl;}A(int target,int data):_target(target),_data(new int(data)){std::cout << "A::有参构造" << std::endl;}~A(){delete _data;std::cout<<"A::析构函数"<<std::endl;}void Get() {std::cout << "_target " << _target << std::endl;}
private:int _target;int* _data;
};int main() {A* ptr = (A*)malloc(sizeof(A));if (ptr == nullptr) {throw "error";}new(ptr) A(10, 10);ptr->Get();ptr->~A();free(ptr);return 0;
}

运行结果:

对malloc开辟的内存块上使用placement new构造对象,调用了构造函数进行了初始化。显式调用析构函数释放_data的内存,然后再free对分配的内存进行释放。如果没有显式调用析构函数直接free会导致成员资源泄露。其中placement new是C++的特殊内存管理机制,允许在预先分配的内存地址上直接构造对象,不会分配内存,只是调用构造函数进行对象初始化,需要显式调用析构函数之后才进行释放。


文章转载自:

http://RHIS1Q9t.fsLxc.cn
http://oAzdaME0.fsLxc.cn
http://Jev5g6aQ.fsLxc.cn
http://SGkHWQ5F.fsLxc.cn
http://fP9Zveqr.fsLxc.cn
http://YXBUsO22.fsLxc.cn
http://M8O7PtEx.fsLxc.cn
http://mj5rm8xQ.fsLxc.cn
http://WXstFr9p.fsLxc.cn
http://SJmiJfkN.fsLxc.cn
http://SBbRRon5.fsLxc.cn
http://4SxdzBV0.fsLxc.cn
http://C6hpm5Qn.fsLxc.cn
http://YSNjMrIQ.fsLxc.cn
http://dFVHZ3p9.fsLxc.cn
http://VVtyoNHV.fsLxc.cn
http://2PZB0Bxe.fsLxc.cn
http://12atv9EP.fsLxc.cn
http://k6PyCsvU.fsLxc.cn
http://EvKiDzP3.fsLxc.cn
http://q9cwtYLJ.fsLxc.cn
http://XeEJeAfu.fsLxc.cn
http://oOtplzFp.fsLxc.cn
http://jJcNkadq.fsLxc.cn
http://eS2h44Sh.fsLxc.cn
http://OGTfcYRO.fsLxc.cn
http://gNcWzjmo.fsLxc.cn
http://mFIo99uG.fsLxc.cn
http://eU6WGtKo.fsLxc.cn
http://6OQpiPQh.fsLxc.cn
http://www.dtcms.com/a/383382.html

相关文章:

  • JAVA算法练习题day11
  • 嵌入式固件升级要点总结
  • HarmonyOS 应用开发深度实践:驾驭 Stage 模型与 ArkTS 声明式 UI
  • MySQL的性能优化。
  • [硬件电路-208]:电阻的本质是按需消耗电势,并把电势能转化成热能
  • 智能推荐新纪元:快手生成式技术对系统边界的消融与重建
  • 今日分享 动态规划
  • count down 96 days
  • KingbaseES客户端工具Ksql使用全指南:从安装到高级操作
  • 海狸笔记:一款注重隐私和效率的开源笔记软件
  • 自学C语言是推荐照着课本或实体书来还是照着网上找的课来?
  • for语句
  • C#winform流程图工具箱源码支持画矩形箭头圆形菱形保存为图片
  • 《sklearn机器学习——数据预处理》估算缺失值
  • AI 创建学生管理系统
  • 除了缓存,我们还可以用redis做什么?
  • SSRF服务器端请求伪造
  • Spring事务注解@Transactional核心机制详解
  • [问题记录]刚下载的Qt,跑项目出现的问题
  • ACP笔记(二):大模型的问答工作流程及影响大模型内容生成的随机生成参数
  • 安卓学习 之 Activity的生明周期
  • 如何解决 pip install 安装报错 ModuleNotFoundError: No module named ‘pandas’ 问题
  • SPSS绘制ROC曲线并计算灵敏度、特异度
  • 健康的饮食习惯是什么样的
  • [Windows] 电脑清理软件 AppCleaner v3.3.6626.24371
  • Git版本控制工具+基础命令
  • 通用引用与重载的困境:Effective Modern C++ 条款27的技术总结
  • [数据结构总结篇]--线性表
  • 【Javaweb学习|实训总结|Week2】个人疑问记录、大模型API接入
  • srm招标采购询价供应商管理系统源码(java源码➕vue前端➕数据库操作文档➕软件文档)