内存专题:
1.左值与右值的概念
从最开始的时候,可能通过等号左右来进行左右值的区分。
不过从c++11开始已经有了变化。
有两个属性可以用于描述值的类别
- 具名(identity):变量是有名字的;可以确定表达式是否与另一表达式指代同一实体。
- 可被移动:移动构造函数等具备移动的能够绑定与这个表达式。
这两个属性能够描述5大类型:
1.左值 :lvalue    具名且不可移动
2.将亡值:xvalue  具名且可被移动
3.纯右值:prvalue 不具名且可被移动
4.泛左值:glvalue 只要具名就行,移不移动
5.右值:rvalue    可被移动的表达式
右值:
右值的特征:无法对右值进行取地址操作
参考说法[]:https://www.zhihu.com/question/26203703
右值、右值引用的概念会广泛应用于移动语义和完美转发
2.智能指针
智能指针与内存关系密切
详解智能指针:[]:https://blog.csdn.net/zr1996106/article/details/123987368
智能指针的原理:
智能指针存放在栈上,利用栈上对象出作用域之后自动析构的特点实现。
3.unique_ptr
独占式智能指针删除了带左值引用的拷贝构造函数和拷贝赋值运算符,但是unique_ptr定义了带右值引用的拷贝构造函数和拷贝赋值运算符
用delete 关键字删除了相关函数
unique_ptr 虽然名字叫指针,用起来也很像,但它实际上并不是指针,而是一个对象。
它也没有定义加减运算,不能随意移动指针地址,这就完全避免了指针越界等危险操作
unique_ptr什么时候会释放:
在下列两者之一发生时用关联的删除器释放对象:
销毁了管理的 unique_ptr 对象
通过 operator= 或 reset() 赋值另一指针给管理的 unique_ptr 对象。
通过调用 get_deleter()(ptr) ,用潜在为用户提供的删除器释放对象。默认删除器用 delete 运算符,它销毁对象并解分配内存。
只有非 const 的 unique_ptr 能转移被管理对象的所有权给另一 unique_ptr 。若对象的生存期为 const std::unique_ptr 所管理,则它被限定在创建指针的作用域中。
4.智能指针的成员函数一般有哪几类?
修改器:release 、reset、swap
观察器:get
5.share_ptr
引用计数放在堆上
6.auto_ptr为什么不推荐用?
转移对象后会留下悬空指针,访问悬空指针会引发程序崩溃
7.智能指针能够管理数组吗 string数组能管理吗?
shared_ptr不支持下标访问,成员访问只能通过get获取指针后再去访问成员
shared_ptr定义的数组需要指定deleter,因为shared_ptr的默认deleter是删除管理的对象,但是,使用new[]进行分配内存时,需要用delete [] 而不是delete。
unique_ptr可以直接使用下标访问,
7.智能指针的强交叉引用(循环引用问题)
8.深拷贝与浅拷贝的区别(与内存和指针相关)
“深拷贝和浅拷贝的区别:浅拷贝主要是对指针的拷贝,拷贝后两个指针指向同一个内存空间,深拷贝需要不但对指针进行拷贝,并对指针指向的内容进行拷贝,经过深拷贝后的指针是指向两个不同地址的指针。 ”
所以,在对含有指针成员的对象进行拷贝时,必须要自己定义拷贝构造函数,使拷贝后的对象指针成员有自己的内存空间,即进行深拷贝.
9.字节对齐的算法
基础的字节对齐:
- 最小位域对齐
- 最小字节对齐
- 默认字节对齐
- 最大字节对齐
- 编译器规则
- 联合体规则
10.c++编译过程以及编译后(可执行程序)内存分配,其中bss段如何理解?
可执行程序的内存分布一般先是堆栈,然后是堆,然后是.bss端到.data端。最后是程序代码区。
11.可执行程序的后缀是什么?它的内存开始地址是多少?空间范围是多少?
在Linux下可执行程序没有后缀 看写编译指令的时候注明的程序名是什么。 而Windows下的可执行程序一般是.exe
可执行程序的内存分布一般先是堆栈,然后是堆,然后是.bss端到.data端。最后是程序代码区。
关于内存开始地址和空间范围:参考网址:[]:https://blog.csdn.net/u014288396/article/details/116086999
12.怎么理解引用与指针,为什么有了指针还需要引用?
- 指针常常容易带来问题:操作野指针、操作空指针、指针的值遭到修改。
- 引用的引入是为了实现运算符重载,并且底层实现实质也还是指针的运用,明面上没有使用值传递。但是兼容C语言没有删去指针。
- 用户自定义的类型最好用引用传参,这样可以避免不必要的构造函数和析构函数调用,但是对于像int,long,char一类的内置类型,按值传参会比按引用传参更高效。
13.引用与指针的相同和区别?
c++ 之中的引用的本质上是指针,底层是一个指向被引用对象的指针。而每一个使用引用的地方该指针被自动解引用了。
引用被封装的很好,必须初始化。从应用上来说他与指针截然不同。
14.拷贝构造函数为什么必须是引用?
传值的方式会调用该类的拷贝构造函数 然后导致无限递归。
13.new和malloc的相同和区别
相同的地方,二者都是动态内存分配,由程序员进行申请和释放。new虽然在自由存储区申请内存,但一般的C++编译器都以堆为自由存储区。
主要区别:是否调用构造和析构;
具体的细节[]:https://www.zhihu.com/question/406164583
我一般用new  new 更安全更便捷
- 安全:new可以初始化分配内存那一块的值,而malloc却是设置随机的值。 申请失败直接抛出异常。
- 便捷:对于变量new无需考虑申请内存大小,而malloc得计算 可以直接new一个数组,malloc得自己计算大小,而且malloc返回的是void* ,需要使用类型强转,而new 根据类型推导直接返回相应指针。
14.new的底层实现是malloc吗?
看编译器,大部分是
15.c++内存分配 new/delete new[]/deletep[]的区别?
首先二者不能混用。必须成对使用,主要问题出现在detele 处 ,数组的话是记录了大小的,那么在析构时需要释放掉相应大小的内存,而普通只需要根据类型直接释放掉类型大小的内存即可。
14.malloc的底层实现
调用malloc 函数的实质是它有一个将可用的内存块连接为一个长长的列表的所谓空闲链表。 调用 malloc()函数时,它沿着连接表寻找一个大到足以满足用户请求所需要的内存块。 然后,将该内存块一分为二(一块的大小与用户申请的大小相等,另一块的大小就是剩下来的字节)。 接下来,将分配给用户的那块内存存储区域传给用户,并将剩下的那块(如果有的话)返回到连接表上。
13.堆分配的过程
14.堆在进程(程序)的内存分布
15.堆分配的算法
16.数组到底存放在哪里
数组指针本身存放在栈,而数组成员在堆中。
17.什么时候会调用拷贝构造?
- 用一个对象去初始化另一个对象时,会调用拷贝构造函数
- 对象以值传递的方式传递给函数参数时,会调用拷贝构造函数
- 函数的返回值是函数体内局部对象的类的对象时
 18.vector的内存是如何增长的?vector的底层实现?
19.利用迭代器删除元素会发生什么?
(1)对于关联容器(如map,set,multimap,multiset),删除当前的iterator,仅仅会使当前的iterator失效,只要在erase时,递增当前的iterator即可。这是因为map之类的容器,使用了红黑树来实现,插入,删除一个结点不会对其他结点造成影响。使用方式如下例子:
(2)对于序列式容器(如vector,deque等),删除当前的iterator会使后面所有元素的iterator都失效。这是因为vector,deque使用了连续分配的内存,删除一个元素导致后面所有的元素会向前移动一个位置。不过erase方法可以返回下一个有效的iterator。
(3)对于list来说,它使用了不连续分配的内存,并且它的erase方法也会返回下一个有效的iterator,因此上面两种正确的方法都可以使用。
本文来自博客园,作者:快乐过了阈值,转载请注明原文链接:https://www.cnblogs.com/black-worrior-2000/p/16565354.html
墨愁前路无知己,天下谁人不识君。
 
                    
                 
                
 
 
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号