直接操作内存带来效率的同时,也带来了痛苦:当程序比较复杂时,这些指向内存片断、对内存进行管理的指针可能会在多个函数或者摸块之间传递,这样就导致这些内存资源没有明确的所属对象,使得程序找不到合适的时机释放这些内存资源,而指向这些内存资源的指针就成为“野指针”。没有家长看管的孩子是“野孩子”,没有所属对象管理的指针就是“野指针”。
因为没有明确的所属关系,一些在多个模块中共亨的资源指针很容易成为“野指针”,从而导致多种内存汸问的问题。首先,因为共享某个内存块指针的多个模块并不拥有这个指针,它们只是使用这些指针,并不负责释放这些指针所指向的内存资源,这可能会导致程序的内存泄露。其次,因为这些指针被多个模块所共享,这可能会导致某个指针所指向的内存资源巳经被释放,但是另外的模块又试图访问这个指针所指向的内存资源,最终导致内存访问错误。
C++语言对内存直接访问的支持使得程序员在享受内存直接访问所带来的高性能和髙灵活性的间时,不得不小心地维护程序的健壮性。程序员都在盼望,如果指针可以更“聪明”一点,自己知道自己该什么时候释放资源就好了。作为程序员,只在需要的时候去申请内存资源,至于何时释放这些内存资源,就由这些"聪明”的指针自己去处理好了。程序员盼星星、盼月亮,终于盼来了完美解决这一问题的“聪明”的智能指针一一shared_ptr.
为什么智能指针shared_ptr这么聪明,可以知道在合适的时机释放它所管理的内存资源?其实,Shared_ptr背后的管理机制并不复杂,它通过对所管理的内存资源进行引用计数来达到对这个资源的管理:当新增一个shared_ptr对该资源进行管理时,也就是新增一个指向此资源的shared_ptr时,就将该资源的引用计数加1,反之,当减少一个shared_ptr对该资源进行管理时,就将该对象的引用计数减1,如果该资源的引用计数为0,说明没有任何指针对其进行管理,就自动调用delete释放其所占用的内存资源。
#include "stdafx.h" #include <iostream> #include <memory> using namespace std; void main() { shared_ptr<int> pFirst( new int ); //这时,只有pFirst这个指针指向这块int类型的内存, //所以这时的引用计數是1 cout<<"当前引用计数:"<<pFirst.use_count()<<endl; { //创建另外一个shared_ptr,并用pFirst对其进行赋值, //让它们指向同一块内存资源 shared_ptr<int> pCopy = pFirst; //因为pFirst和pCopy都指向这一块内存资源, //所以这一资泺的引用计教增加为2 cout<<"当前引用计數:"<<pFirst.use_count()<<endl; } //当超出pCopy的可见域,pCopy结束其生命周期后, //指向这一内存资源的只有pFirst指针,所以引用计数减为1 cout<<"当前引用计数:"<<pFirst.use_count()<<endl; //当程序最终结束执行返回,pFirst:指针也结束其生命周期后, //从此没有任何指针指向此内存资漶,引用计数减为0,内存资源自动得到释放 system("pause"); } /* 当前引用计数:1 当前引用计數:2 当前引用计数:1 */
总结起来,当出现以下情况时应该优先考虑使用shared_ptr:
I 有多个使用者共同使用同一个对象(指针指向一个需要shared的对象),而没有一个明显的拥有者时,谁来释放就是一个问题; II 一个对象的复制操作很昂贵; III 要把指针存入标准库容器; IV 要传送对象到库或从库获取对象,而这些对象没有明确的所有权; V 当管理需要特殊清除方式的资源时,这时可以通过定制shared-ptr的删除器来实现。
虽然智能指针shared_ptr通过引用计数的方式完美地解决了C++语言中的内存管理问题,但是,同样是因为引用计数,却又给shared_ptr带来两个新问题。
I 体积问題
因为shared_ptr需要进行引用计数,所以它需要額外的内存空间来保存当前内存资源的引用数,这使得一个shared_ptr。指针将占用40个字节的内存空间,是一个普通指针所占用内存空间的整整10倍。如果要在程序中保存和处理大量的shared_ptr,shared_ptr的体积问题将是一个“大”问题。
II 性能问题
一方面,因为引用计数,shared_ptr需要在运行时对引用计数进行管理和维护,这样就必然需要消耗额外的计算资源,影响程序的性能,另一方面,share_ptr使用了大量的虚函数,虚函数的使用也带来了一定的性能损失。
这真是成也“引用计数”,敗也“引用计数”。不过不用担心,C++为我们提供了一个瘦身版的智能指针-unique_ptr。使用unique_ptr,可以很好地解决shared_ptr因为引用计数所遇到的这些问题。跟shared_ptr—样,unique_ptr也可以对它所关联的内存资源进行管理,当unique_ptr销毁时,同样会自动释放它所管理的内存资源。但与shared_ptr不同的是,unique_ptr没有引用计数,也就是说,某一个内存资源,只允许有一个unique_ptr与之关联,对其进行管理。因为没有引用计数,这就使得uniquc_ptr避免了shared_ptr的体积问题和性能问題,成为shared_ptr在某些情况(需要使用大量智能指针而又无须对智能指针进行复制)下的一个很好的替代,在使用上,unique_ptr跟shared_ptr基本相同,两者唯一的差别就是,unique_ptr不可以进行复制,换句话说,不能有两个unique_ptr关联同一内存资源。
-End-
本文暂时没有评论,来添加一个吧(●'◡'●)