内存分配:

静态存储区:

  1. 局部static对象
  2. 类的static数据成员
  3. 定义在任何函数之外的变量

栈区:

  1. 函数内的非static对象

动态内存分配的方式有:

  1. new和delete
  2. 智能指针(shared_ptr、unique_ptr、weak_ptr)
  3. allocator类
  4. malloc和free

直接管理内存:

运算符new分配内存,delete释放new分配的内存。

int* p = new int ();//new表达式在自由空间构造一个对象,并返回指向该对象的指针。
delete p;
int* pi = new int[10]();//分配一个10个int的数组,pi指向第一个int。

默认情况下,动态分配的对象是默认初始化的,这意味着内置类型或者组合类型的对象的值是未定义的,而类类型对象将用默认构造函数进行初始化
new分配const对象是合法的,但const对象必须进行初始化
如果一个程序用光了所有可用的内存,new表达式会失败,并抛出bad_alloc异常,该异常可以通过nothrow阻止,阻止异常抛出的new称为定位new

int* p1 = new int;//如果分配失败,new抛出std::bad_alloc。
int* p2 = new (nothrow)int;//如果分配失败,new返回一个空指针。

delete表达式也执行两个动作:销毁一个给定的指针指向的对象;释放对应的内存。
传递给delete的指针必须指向动态分配的内存,或者是一个空指针,释放一个并非new分配的内存,或者将相同的指针值释放多次,其行为是未定义的
释放动态数组时,数组中的元素按逆序销毁
释放一个const动态对象,只要delete指向它的指针即可。

const int* pci = new const int(1024);
delete pci;

直接管理内存容易犯的错:

  1. 忘记delete内存(内存泄漏)
  2. 使用已经释放掉的对象
  3. 同一块内存释放两次

空悬指针/野指针(dangling pointer):指向一块曾经保存数据对象但现在已经无效的内存的指针。
产生原因:指针变量声明时未初始化或者指针被delete或free后未置为nullptr以及指针操作超越了变量的作用范围

智能指针:

shared_ptr允许多个指针指向同一个对象
unique_ptr“独占”所指向的对象
weak_ptr指向一个shared_ptr管理的对象,它不控制指向对象的生存期。

shared_ptr:
初始化:

shared_ptr<string> p1;//默认初始化的智能指针保存着一个空指针

智能指针的使用方式与普通指针类似。解引用一个智能指针返回它指向的对象,如果在一个条件判断中使用智能指针,效果是检测它是否为空。

if (p1 && p1->empty()) {*p1 = "hi";//如果p1指向一个空string,解引用p1,将一个新值赋予string。
}

make_shared函数:
类似顺序容器的emplace成员,make_shared用其参数来构造给定类型的对象。

shared_ptr<int> pi = make_shared<int>(42);

引用计数:
每个shared_ptr都有一个关联的计数器,通常称其为引用计数。无论何时我们拷贝一个shared_ptr,或将其作为参数传递给一个函数以及作为一个函数的返回值时,它所关联的计数器就会递增。当我们给shared_ptr赋予一个新值或者是shared_ptr被销毁时,计数器就会递减。当一个shared_ptr的计数器变为0,他就会自动释放自己所管理的对象。

程序使用动态内存的三个原因:

  1. 程序不知道使用多少个对象(容器类)
  2. 程序不知道所需对象的具体类型
  3. 程序需要在多个对象间共享数据

shared_ptr与new的结合:
接受指针参数的智能指针构造函数是explicit的,因此我们不能将一个内置指针隐式转换为一个智能指针,必须使用直接初始化的形式

shared_ptr<int> p1 = new int(1024);//错误
shared_ptr<int> p1(new int(1024));//正确

如果想用shared_ptr管理动态数组,必须提供自己定义的删除器,并且不支持下标操作。

shared_ptr<int> sp(new int[10],[](int *p){delete [] p ;});
sp.reset();

正确使用智能指针的规范:

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

unique_ptr:
当我们定义unique_ptr时,需要将其绑定到一个new返回的指针上,而且必须采用直接初始化的形式。
由于unique_ptr“独占”它指向的对象,因此unique_ptr不支持拷贝或赋值操作
虽然我们不能拷贝和赋值unique_ptr,但可以调用release或reset将指针所有权从一个(非const)unique_ptr转移给另一个unique:

unique_ptr<string> p1(new string("first"));
unique_ptr<string> p2(p1.release());//将所有权从p1转向p2,p1被置为空
unique_ptr<string> p3(new string ("second"));
//将所有权从p3转移给p2.
p2.reset(p3.release());//reset释放了p2原来指向的内存。

unique_ptr可以管理动态数组,必须在对象类型后面跟一对空方括号,支持下标操作。

unique_ptr<int[]> up(new int[10]);
up.release();//自动用delete[]销毁其指针。
for(size_t i = 0 ; i != 10 ; i++)
{up[i] = i;
}

weak_ptr:
weak_ptr不控制所指向的对象的生存期,指向一个由shared_ptr管理的对象。将一个weak_ptr不会改变shared_ptr的引用计数。一旦最后一个指向对象的shared_ptr被销毁,对象就会被释放。
由于对象可能不存在,不能使用weak_ptr直接访问对象,必须调用lock。此函数检查weak_ptr指向的对象是否仍存在。如果存在,lock返回一个指向共享对象的shared_ptr。
可以解决两个shared_ptr互相引用的问题。

allocator类:

将内存分配和对象构造分离开,提供一种类型感知的内存分配方法,他分配的内存是原始的、未构造的。
定义一个allocator对象,必须指明这个allocator可以分配的对象类型。当一个allocator对象分配内存时,它会根据给定的对象类型来确定恰当的内存大小和对齐位置:

allocator<string> alloc;//可以分配string的allocator对象
auto const p = alloc.allocate(n);//分配n个未初始化的string。
auto q = p;
alloc.construct(q++);//*q为空字符串
alloc.construct(q++,10,'c');//*q为cccccccccc
alloc.construct(q++,"hi");//*q为hi
cout<<*p<<endl;//正确:使用string的输出运算符
cout<<*q<<endl;//灾难:q指向未构造的内存
while(q!=p)alloc.destroy(--q);//释放我们真正构造的string
//destory接受一个指针,对指向的对象执行析构函数。
alloc.deconstruct(p,n);//通过deallocate释放内存。
//传递给deallocate的指针不能为空,它必须指向由allocate分配的内存。而且传递给deallocate的大小参数必须与调用allocated分配内存时提供的大小参数具有一样的值。

动态内存分配与智能指针相关推荐

  1. 动态内存管理和智能指针 2.0 -- shared_ptr

    shared_ptr出现原因 通过第一章的学习,我们知道不管是auto_ptr合适scoped_ptr都是存在缺陷的,于是我们必须想出一个方法既能很好的管理我们的内存,而且在使用的时候,可以多个指针指 ...

  2. 【C 语言】内存管理 ( 动态内存分配 | 栈 | 堆 | 静态存储区 | 内存布局 | 野指针 )

    相关文章链接 : 1.[嵌入式开发]C语言 指针数组 多维数组 2.[嵌入式开发]C语言 命令行参数 函数指针 gdb调试 3.[嵌入式开发]C语言 结构体相关 的 函数 指针 数组 4.[嵌入式开发 ...

  3. C和指针之动态内存分配常见问题和总结

    1.动态内存分配常见问题       1) 结构体成员指针未初始化       2)为指针分配内存太小       3)内存分配成功,但是没初始化       4)内存越界,内存泄漏,free多次或者 ...

  4. C语言学习笔记10-指针(动态内存分配malloc/calloc、realloc、释放free,可变数组实现;Tips:返回指针的函数使用本地变量有风险!;最后:函数指针)

    C语言:指针 1. 指针:保存地址的变量 *p (pointer) ,这种变量的值是内存的地址.   取地址符& 只用于获取变量(有地址的东西)的地址:scanf函数-取地址符   地址的大小 ...

  5. C和指针之动态内存分配之编程练习3

    1.问题 编写一个函数,从标准输入读取一个字符串,把字符串复制到动态内存分配的内存中,并返回该字符串的拷贝,这个函数不应该对读入字符串的长度作任何限制!             2.代码实现 #inc ...

  6. C++类与动态内存分配

    11.10 类与动态内存分配 通常,最好是在程序运行时(而不是编译时)确定诸如使用多少内存等问题.对于在对象中存储姓名来说,通常的C++方法是,在类构造函数中使用new运算符在程序运行时分配所需的内存 ...

  7. 第12章-cpp类和动态内存分配

    本章内容包括: • 对类成员使用动态内存分配. • 隐式和显式复制构造函数. • 隐式和显式重载赋值运算符. • 在构造函数中使用new所必须完成的工作. • 使用静态类成员. • 将定位new运算符 ...

  8. 释放变量所指向的内存_C++动态内存分配(学习笔记:第6章 15)

    动态内存分配[1] 动态申请内存操作符 new new 类型名T(初始化参数列表) 功能: 在程序执行期间,申请用于存放T类型对象的内存空间,并依初值列表赋以初值. 结果值: 成功:T类型的指针,指向 ...

  9. 动态内存分配与柔性数组

    什么时动态内存分配 一般我们写程序都是在栈区分配空间,如果我们想根据需求想随时存放随时释放数据,堆区可以实现根据需求想系统申请所需大小的空间. 建立内存的动态分配 内存的动态分配是通过系统提供的函数来 ...

最新文章

  1. OpenCV 笔记(07)— Mat 对象输出格式设置(Python 格式、CSV 格式、NumPy 格式、C 语言格式)
  2. jnotify监控linux系统,jnotify linux使用记录
  3. 这些 AI 大咖的实践干货,从事人工智能的你应该知道
  4. 解析CleanMyMac隐私保护内容与使用
  5. 第十六届智能车竞赛创意组比赛-筹划初稿
  6. Hibernate Annotation _List/Map
  7. ExcelJS —— Node 的 Excel 读写扩展模块2
  8. js javaScript array 取指定元素索引、判断是否相同、重复、过滤数据
  9. YBTOJ洛谷P2042:维护数列(平衡树)
  10. CSS: 解决100% 高度失效 height 100% is not working when scrolling down page
  11. 笔记-JavaWeb学习之旅4
  12. Android 中插件的编写方法
  13. 接口测试(二)--APP抓包
  14. axios 上传文件_聚是一团火散作满天星,前端Vue.js+elementUI结合后端FastAPI实现大文件分片上传...
  15. Cannot declare member function ...to have static linkage错误
  16. 有关目标的SMART法则
  17. docker run 报错 Bind for 0.0.0.0:80 failed: port is already allocated.解决方案
  18. 微信小程序自定义导航栏(带汉堡包菜单)
  19. 十人拼团一人得产品幸运【拼够够】我们来看具体的模式吧
  20. 整理oracle Hints 用法大全

热门文章

  1. codeup27980 乘法算式(NOIP1996普及组第1题)
  2. unity制作GTA5(一) —— Michael人物
  3. c51单片机汇编语言语法错误,关于51单片机汇编语言一些注意事项
  4. layui实现带搜索功能的select
  5. 以二进制方式打开文件并显示
  6. 计算机一级调薪后的工资,义务教育教师基本工资提高10%取消!2019年调资后你的待遇是涨还是降?...
  7. 洛谷P4113 [HEOI2012]采花 题解
  8. 【每日新闻】企业微信与微信消息互通正式开放内测 | IBM宣布针对云原生应用推出Microclimate开发平台
  9. ELO用户忠诚度评分建模
  10. 乌班图安装nginx