栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

C++学习笔记07--动态内存管理

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

C++学习笔记07--动态内存管理

01new/delete 堆vs栈

计算机世界里的“堆栈”你真的懂吗? - 知乎

栈内存特点:        更好的全局性,对象自动销毁

堆内存的特点:        运行期动态扩展,需要显示释放

int x;  x在栈区
x=2;
cout< 
int *fun()
{
    int *res=new int(4); 合法 res开辟在堆区  作为函数返回值未销毁 y指向res 
    return res;
}
int *fun2()
{
    int res2=3; 不合法 res2开辟在栈区 作为函数返回值后已销毁 z指向res2及指向一个已经销毁的地址
    return &res;
}
int main()
{
    int *y=fun();    
    cout<<*y< 
new 

C++通常需要new和delete来构造和销毁对象

new:构造对象      先分配内存  再构造对象

delete:对象销毁    先销毁对象   再释放内存

  

new的形式:

1.构造单一的对象/对象数组

int main()
{
    int x;
    int *y=new int;
    delete y;

    int *z=new int[5]; 开辟20个字节的内存空间 保存5个int的对象   返回首个int的地址
    int *a=new int[3]{1,2,3};
    cout<

nothrow new    不抛异常的new   需要头文件#include

#include

int *y=new(std::nothrow)int[5]{};
if(y==nullptr){....}  如果y经过一系列操作后指向空了  不让编译器报异常从而停止程序
delete []y

placement new 已有内存  只构造对象

char ch[sizeof(int)];
int *y=new(ch)int(4);   在ch包含的内存上,创建对象  此处是栈内存  
cout<<*y< 

new auto

int *y=new auto(3);   可以推导出int类型
int *x=new auto ;  error
delete

delete常见用法: 

-销毁单一对象或者数组   delete pty   ;       delete[ ] ptr

-placement delete   只销毁对象 不释放内存

  

Notes:

--根据分配的是单一对象还是数组,采用相应的delete

--delete nullptr  

        int *x=nullptr;int *y=0; delete x;delete y;   delete 什么也不做

--不能delete一个非new返回的内存   int x; delete x;  error

--同一块内存不能delete多次

int *ptr=new int[5];
int *ptr2=ptr+1;
delete []ptr2  error

int *x=new int(4);
delete x;
cout<<*x< 
02智能指针 

【C++】智能指针详解_Billy12138的博客-CSDN博客_智能指针参考资料:《C++ Primer中文版 第五版》 我们知道除了静态内存和栈内存外,每个程序还有一个内存池,这部分内存被称为自由空间或者堆。程序用堆来存储动态分配的对象即那些在程序运行时分配的对象,当动态对象不再使用时,我们的代码必须显式的销毁它们。在C++中,动态内存的管理是用一对运算符完成的:new和delete,new:在动态内存中为对象分配一块空间并返回一个指向该对象的指针,delet...https://blog.csdn.net/flowing_wind/article/details/81301001

使用new/delete的问题:  内存所有权不清晰,容易产生不销毁,多销毁的情况----

解决方法--智能指针

C++ 智能指针底层是采用引用计数的方式实现的。简单的理解,智能指针在申请堆内存空间的同时,会为其配备一个整形值(初始值为 1),每当有新对象使用此堆内存时,该整形值 +1;反之,每当使用此堆内存的对象被释放时,该整形值减 1。当堆空间对应的整形值为 0 时,即表明不再有对象使用它,该堆空间就会被释放掉。

int *fun()
{
    int *res=new int(100);
    return res;
}
int main()
{
    int *y=fun();  main 和fun谁拥有res的所有权  谁来释放堆区内存不清晰
}

int *fun2()
{
    static int res=200; 静态局部变量既不在堆区也不再栈区 
    return &res;
}
int main()
{
    int *y=fun();  通常程序执行完  系统自动销毁res
}
shared_ptr 共享指针

auto_ptr      C++98和C++03引入 

shared_ptr  unique_ptr   weak_ptr   C++11引入

  

shared_ptr-----基于引用计数的内存共享解决方案  包含头文件#include

多个 shared_ptr 智能指针可以共同使用同一块堆内存。并且,由于该类型智能指针在实现上采用的是引用计数机制,即便有一个 shared_ptr 指针放弃了堆内存的“使用权”(引用计数减 1),也不会影响其他指向同一堆内存的 shared_ptr 指针(只有引用计数为 0 时,堆内存才会被自动释放)

1.基本用法

#include
#include
int main()
{
    std::shared_ptrx(new int(4));  初始化
    cout<y=x;
    cout< 

2.get()/reset()用法

std::shared_ptrfun()
{
    std::shared_ptrres(new int (100));
    return res;
}
void fun(int *ptr){....}

int main()
{
    auto y=fun();
    cout<<*y< 
#include
#include
std::shared_ptrfun()
{
    std::shared_ptrres(new int (23));
    return res;
}
int main()
{
    auto y=fun();
    y.reset(new(int(3)));  把原来指向的内存释放掉  关联新的内存

    y.reset((int*)nullptr);不关联任何内存 nullptr为nullptr_t  故需要转化为int*
    y.reset();
}

3.指定回收逻辑

void fun(int *ptr)
{
    cout<<"fun in called"<x(new int(3),fun);  x指向的内存引用计数为0时,会调用fun作为deleter 
                                             而不是默认的deleter
}

4.std::make_shared  (引入优化+构造对象)

std::shared_ptrptr(new int(3));
std::shared_ptrptr2=std::make_shared(3);
auto ptr3=std::make_shared(3);
make_shared引入了优化 将关联的内存与维护引用计数的内存放的尽可能的近  使程序读取一次缓存即可  优化了程序的性能.

5.shared_ptr C++17引入     make_shared分配数组   c++20引入

C++17之前  数组指针需要指定回收逻辑,C++17引入了对数组的支持

std::shared_ptrptr(new int [5]);
auto ptr2=std::make_shared(5);

6.shared_ptr<>管理的对象不要调用delete销毁

智能指针陷阱:
(1)不使用相同的内置指针值初始化(或reset)多个智能指针。
(2)不delete get()返回的指针
(3)不使用get()初始化或reset另一个智能指针
(4)如果你使用get()返回的指针,记住当最后一个对应的智能指针销毁后,你的指针就变为无效
(5)如果你使用智能指针管理的资源不是new分配的内存,记住传递给它一个删除器

std::shared_ptrx(new int(3));
delete x.get(); 将x指向的内存销毁,当程序执行完销毁x时,x此时为悬挂指针,调用析构函数,再次销毁指向的内存,故重复释放

std::shared_ptry(x);  x和y共享一套引用计数和内存
std::shared_ptry(x.get()); error 重复释放  x y只共享指向的内存

int *ptr=new int(3);
std::shared_ptri(ptr);
std::shared_ptrj(ptr);error重复释放
unique_ptr 独占内存

某个时刻只能有一个unique_ptr指向一个给定对象,由于一个unique_ptr拥有它指向的对象,因此unique_ptr不支持普通的拷贝或赋值操作。

1.基本用法

unique_ptr不支持复制  但是可以移动  也可为unique_ptr指定回收逻辑

std::unique_ptrx(new int(3));
std::unique_ptry=x;error unique_ptr不支持复制  但是可以移动
std::unique_ptry=std::move(x); 将亡值x 将资源全部给y
std::cout<fun()
{
    auto res=std::make_unique(4);
    return res;
}

int main()
{
    std::unique_ptrx=fun();  res将所有权转让给x;
}
void fun(int *ptr)
{
    std::cout<<"fun is called"<x(new int(3),fun);
    std::unique_ptry(new int(3),fun);  需要decltype
}
weak_ptr --防止循环引用引入的智能指针

weak_ptr是一种不控制所指向对象生存期的智能指针,它指向一个由shared_ptr管理的对象,将一个weak_ptr绑定到一个shared_ptr不会改变shared_ptr的引用计数。一旦最后一个指向对象的shared_ptr被销毁,对象就会被释放,即使有weak_ptr指向对象,对象还是会被释放。

可以和shared_ptr共享内存,但是不增加引用计数

struct Str
{
    std::weak_ptrm_nei;
    ~Str()
    {
        cout<<"~Str()is called"<x(new Str{});
    std::shared_ptry(new Str{});
    x->m_nei=y;
    y->m_nei=x;  循环引用   若m_nei是std::shared_ptr则不能释放x y
} 
03动态内存相关问题

1.sizeof不会返回动态分配的内存大小

int *ptr=new int (3);
int *ptr=new int [3];
cout<x;
cout< 

2.使用分配器allocator来分配内存

std::allocatoral;
int *ptr=al.allocator(5); 只分配包含5个int的内存 不构造对象 包含了对齐内存的操作
al.deallocator(ptr,3)  释放内存

3.使用malloc/free来管理内存  C语言

//void * malloc(size_t size)
int *p1=malloc(4*sizeof(int));
int *p2=malloc(sizeof(int [4]));
int *p3=malloc(4*sizeof(*p3));;
.......
free (p1);
free (p2);
free (p3);
malloc只分配字节  只关注分配内存的大小  不构造对象  内存也不一定对齐

经典面试题: new 和malloc 的区别?

C++ new和malloc的区别_Linux猿的博客-CSDN博客_c++malloc

经典面试题之new和malloc的区别_Datou_Nie的博客-CSDN博客_new和malloc的区别

1.使用new操作符申请内存分配时无须指定内存块的大小,编译器会根据类型信息自行计算。而malloc则需要显式地指出所需内存的尺寸,不能对齐内存.

2.new会先调用operator new函数,申请足够的内存(通常底层使用malloc实现)。然后调用类型的构造函数,初始化成员变量,最后返回自定义类型指针。delete先调用析构函数,然后调用operator delete函数释放内存(通常底层使用free实现.)

-malloc/free是库函数,只能动态的申请和释放内存,无法强制要求其做自定义类型对象构造和析构工作

3.new做两件事:分配内存和调用类的构造函数,delete是:调用类的析构函数和释放内存。而malloc和free只是分配和释放内存。

-new操作符从自由存储区(free store)上为对象动态分配内存空间,而malloc函数从堆上动态分配内存。自由存储区是C++基于new操作符的一个抽象概念,凡是通过new操作符进行内存申请,该内存即为自由存储区。而堆是操作系统中的术语,是操作系统所维护的一块特殊内存,用于程序的内存动态分配,C语言使用malloc从堆上分配内存,使用free释放已分配的对应内存。自由存储区不等于堆,如上所述,布局new就可以不位于堆中

4.使用aligned_alloc来分配对齐内存   256/4=64个int

5.动态内存与异常安全(产生异常,也会释放内存)

void fun()
{
    int *ptr=new int(3); 
    ...                 可能有异常导致内存不能释放  使程序终止
    delete ptr;
}
void fun()
{
    std::shared_ptr(new int(3));
}                       使用智能指针  保证异常下  也能正常释放内存

6.C++对垃圾回收的支持

Garbage collector support

-开辟单独线程(不断检测堆区的内存)消耗资源

-不能对对象的生命周期精确的控制

持续更新............................

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/972010.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号