动态内存与智能指针
来源:互联网 发布:恒生电子 知乎 编辑:程序博客网 时间:2024/05/17 10:05
两种智能指针:
- shared_ptr : 允许多个指针指向同一对象
- unique_ptr :“独占”所指向的对象
shared_ptr
shared_ptr类:
类似vector,智能指针也是模板,所以创建方式为:
shared_ptr<string> p1;//空智能指针shared_ptr,可以指向stringshared_ptr<list<int>> p2;//空智能指针shared_ptr,可以指向int的list
其他操作方式与普通操作方式都类似:
*p //解引用p -> mem //等价于(*p).memswap(p,q) //交换p,q中的指针p.swap(q)make_shared<T>(args) //返回一个shared_ptr,指向一个动态分配的对象(T类型,以args初始化的)shared_ptr<T>p(q) //拷贝,此操作会增加q的引用计数
make_shared函数:
返回一个shared_ptr,指向一个动态分配的对象(T类型,以args初始化的)
//指向一个值为42的int的shared_ptrshared_ptr<int> p3 = make_shared<int>(42);//指向一个值为"9999999999"的stringshared_ptr<string> p4 = make_shared<string>(10,'9');//p5指向一个值初始化的int,即,值为0shared_ptr<int> p5 = make_shared<int>();
shared_ptr的拷贝,赋值以及销毁对象:
当进行拷贝或赋值操作时,每个shared_ptr都会记录有多少个其他shared_ptr指向的相同的对象
auto p = make_shared<int>(42);//p指向的对象只有p一个引用者auto q(p);//p和q指向相同对象,此对象有两个引用者
一旦一个shared_ptr的计数器变为0,它就会自动释放自己所管理的对象:
auto r = make_shared<int >(42);//r指向的int只有一个引用者r = q; //给r赋值,令它指向另一个地址 //递增q"指向的对象"的引用计数 //递减"r原来指向的对象"的引用计数 //r原来指向的对象已没有引用者,会自动释放
当动态对象不再被使用时,shared_ptr类还会自动释放动态对象。
使用new动态分配和初始化对象:
在自由空间分配的内存是无名的:
int *p = new int;//pi指向一个动态分配、未初始化的无名对象//默认情况下,动态分配的对象时默认初始化的string *ps = new string;//空串(类类型默认初始化)int *pi = new int;//pi指向一个未初始化的int(内置类型的值则是未定义的)string *ps1 = new string;//默认初始化为空stringstring *ps = new string();//值初始化为空stringint *pi1 = new int; //默认初始化;*pi1未定义int *pi2 = new int();//值初始化;*pi2为0int *p1 = new int;//如果分配失败,new抛出std::bad_allocint *p2 = new (nothrow) int;//若分配失败,new返回一个空指针
注:对于定义了自己的构造函数的类类型来说,不管采用默认初始化还是值初始化,对象都会通过默认构造函数来初始化。而对于内置类型,值初始化的内置类型对象有着良好的定义的值,而默认初始化的对象的值则是未定义的。
动态内存的管理非常容易出错:
忘记delete内存。忘记释放动态内存会导致人们常说的“内存泄露”问题
使用已经释放掉的对象。
同一块内存释放两次。
相对于查找和修正这些错误来说,制造出这些错误要简单得多。故坚持只使用智能指针,就可以避免所有这些问题。
shared_ptr和new结合使用:
可以用new返回的指针来初始化智能指针:
shared_ptr<double> p1;//shared_ptr可以指向一个doubleshared_ptr<int> p2(new int(42));//p2指向一个值为42的int
但是,接受指针参数的智能指针构造函数是explicit的,因此,不能将一个内置指针类型转换为一个智能指针,必须使用直接初始化形式:
shared_ptr<int> p1 = new int(1024);//错误:必须使用直接初始化形式shared_ptr<int> p2(new int(1024));//正确:使用了直接初始化形式
shared_ptr指针的一些函数:
shared_ptr<T> p;p.get() //返回一个内置类型指针,指向智能指针所管理的对象shared_ptr<T> p(q) //p管理内置指针q所指向的对象p.reset() //若p是唯一指向其对象的shared_ptr,reset会释放此对象p.reset(q) //内置指针q,会令p指向qp.reset(q,d) //同上,但删除p时不会用delete,而是用d
例如:
shared_ptr<int > p(new int(42));int *q = p.get();//正确:但使用q时要注意,不要让它管理的指针被释放p = new int(1024);//错误:不能将一个指针赋予shared_ptrp.reset(new int(1024));//正确:p指向一个新对象
注:永远不要用get初始化另一个智能指针或为另一个智能指针赋值。
unique_ptr
unique_ptr类:
没有类似make_shared的标准库函数返回一个unique_ptr。当定义一个unique_ptr时,需要将其绑定到一个new返回的指针上。类似shared_ptr,初始化unique_ptr时必须采用直接初始化形式:
unique_ptr<double> p1; //可以指向一个double的unique_ptrunique_ptr<int> p2(new int(42));//p2指向一个值为42的int//注:因为unique_ptr"拥有"它所指向的对象,因此unique_ptr不支持普通的拷贝或赋值操作unique_ptr<string> p1(new string("sssss"));unique_ptr<string> p2(p1);//错误,unique_ptr不支持拷贝unique_ptr<string> p3;p3 = p1; //错误:unique_ptr不支持赋值
unique_ptr的一些操作:
u = nullptr //释放u指向的对象,将u置为空u.release() //u放弃对指针的控制权,返回指针,并将u置为空u.reset() //释放u指向的对象u.reset(q) //若提供了内置指针q,令u指向这个对象u.reset(nullptr)//否则将u置为空//注:release()只是放弃对指针的控制权,并没有释放对象
虽然不能拷贝和赋值unique_ptr,但可以调用release或reset将指针的所有权从一个unique_ptr转移给另一个unique:
//将所有权从p1转移给p2unique_ptr<string> p2(p1.release());//release将p1置为空unique_ptr<string> p3(new string("Trex"));//将所有权从p3转移到p2p2.reset(p3.release());//reset释放了p2原来指向的内存
注意:若我们不用另一个智能指针来保存release返回的指针,我们的程序就要负责资源的释放:
p2.release() ; //错误:p2不会释放内存,而我们丢失了指针auto p = p2.release();//正确:但我们必须记得delete(p)
注:标准库较早版本包含了一个名为auto_ptr的类,就是《Effective C++》中的auto_ptr,与这里的unique_ptr类似,可以把auto_ptr理解为unique_ptr的一个子集,编写程序时应该使用unique_ptr。
weak_ptr类:
weak_ptr是一种不控制所指向对象生存期的智能指针,它指向由一个shared_ptr管理的对象。将一个weak_ptr绑定到一个shared_ptr不会改变shared_ptr的引用计数。
当我们创建一个weak_ptr时,要用一个shared_ptr来初始化它:
auto p = make_shared<int>(42);weak_ptr<int> wp(p);//wp弱共享于p;p引用计数未改变
参考:《C++ primer》《Effective C++》
- 动态内存与智能指针
- 动态内存与智能指针
- 动态内存与智能指针
- 动态内存与智能指针
- 动态内存与智能指针
- 动态内存与智能指针
- 动态内存与智能指针
- 动态内存与智能指针
- 动态内存与智能指针
- 动态内存与智能指针
- 动态内存与智能指针
- C++中的动态内存与智能指针
- C++中的动态内存与智能指针
- C++中的动态内存与智能指针
- (十二)动态内存与智能指针
- C++中的动态内存与智能指针
- C++中的动态内存与智能指针
- C++中的动态内存与智能指针
- node.js指令
- nodejs的下载/安装和使用
- 实现ALV的TOP_OF_PAGE的两种方法(一)
- JQuery优缺点
- ubuntu常用命令2
- 动态内存与智能指针
- Redis 持久化技术
- Linux errno 错误对照表
- Node JS 的安装与使用和dos窗口环境的常用命令
- 在dos中的常用命令
- CCS调试问题记录
- Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?解决方
- Android学习记录
- Java 集合总结