C++内存管理介绍
前言;
C++继承了C语言的指针,一直以来指针的一些问题困扰着开发人员,常见的指针问题主要有:内存泄露、野指针、访问越界等。值得庆幸的是C++标准委员会给我们提供了auto_ptr智能指针,后面又引入了share_ptr
以及weak_ptr
帮助我们正确和安全的使用指针,本文主要是介绍boost库提供的解决方案,期望通过本文能够给你提供一个新的天地。
1 smart_ptr概述
在实际开发时,我们会根据不同的编程场景申请不同的资源,对于这些资源的管理需要一个完善的方案,我们希望在资源释放后,C++能够像java,c#一样不用去手动的释放资源而是由系统自动对资源进行回收。
1.1 RAII进制
C++编程时通常使用这种方法管理资源,申请的资源超过生命周期后,生命的对象自动调用析构函数对资源进行正确回收。如此看来,似乎是完美的解决我们的问题,至少在使用时不用手动释放资源。但是这种资源释放的方法同样存在着缺陷,如果对象是在栈上创建得到,那么会自动调用析构函数,结果也是没有问题的,但是如果对象是通过new在堆上创建的呢?结果是析构函数不能自动被调用,同样需要我们使用delete进行显示析构。如果程序在执行时没有调用析构delete
进行释放资源,那么同样也会存在内存泄露的风险。
new/delete
在编程时一定要遵循配对原则,且要服从谁创建谁释放的规则,这一点不管是新手程序员还是有着丰富编程经验的老手都要认真对待。
1.2 智能指针
从C98开始,C++标准委员会就给我们提供了智能指针:auto_ptr。它部分解决了资源的自动释放问题。
使用方法如下:
std::auto_ptr<int> p (new int);
auto_ptr
的构造函数支持new操作符或者由对象工厂创建的对象指针作为参数。对象一经创建就托管了原始指针,因此它可以使用get方法返回指针对象,如:
*p.get() = 100;
auto_ptr
受到了大家的欢迎,越来越多的人使用这种技术解决了实际编程中大部分得到资源管理的问题,但是,auto_ptr
并不是一种非常完善的技术,也没有覆盖到智能指针的所有领域,尤其是引用计数型的智能指针。同理,在使用auto_ptr
的时候也要注意以下几点,避免auto_ptr
的滥用。
- auto_ptr不能共享所有权,即不要让两个auto_ptr指向同一个对象。
- auto_ptr不能指向数组,因为
auto_ptr
在析构的时候只是调用delete
。 - auto_ptr只是一种简单的智能指针,如有特殊需求,需要使用其他智能指针,比如
share_ptr
。 - auto_ptr不能作为容器对象。
为了解决auto_ptr
的不足,boost库提供了多种类之中从而完善了auto_ptr的不足。这些指针都在boost库的头文件中,
如下所示:
#include <boost/smart_ptr.hpp> using namespace boost;
1.3 scoped_ptr
该类型指针和auto_ptr
类似,但是限制也更加严格,scoped_ptr
对象一旦获取对象的管理权就将一直占用,不能在进行管理权转移。scoped_ptr
像它的名字一样,只能在起作用域内进行使用。使用后会使得代码相对简单且不会增加多余操作。
scoped_ptr使用方法:
scoped_ptr
使用简单,只需要在原来使用new
的地方用scoped_ptr
进行替换即可,
使用方法如下:
scoped_ptr<string> pStr(new string("hello word"));
操作scoped_ptr指针也很简单,使用方式和普通指针一致,如:
//打印指针指向字符串内容 cout<<pAtr<<endl; //打印字符长度 cout<<pAtr->size()<<endl;
需要注意的是:1)此指针对象会进行自动释放,无需使用delete进行释放,如果在实际编程时使用了delete,编译器将会报错,大家不妨可以思考下原因是什么欢迎留言。2)scoped_ptr
是不能进行赋值、拷贝操作得到,生命周期只限于声明的作用域内。
和auto_ptr指针相比,scoped_ptr的不同点如下:
两者都不能作为容器元素,但是原因却不同。auto_ptr
是因为它自身的转义语义,但是scoped_ptr
是因为不支持拷贝和复制。
指针所有权不同,auto_ptr
是可以进行转义得到,但是scoped_ptr
不能进行转义,因为其构造和拷贝函数都是私有的。
1.4 scoped_array
scoped_array
和scoped_ptr
基本相同,根本区别是scoped_array
是指向数组的,封装了new[],弥补了指向数组的智能指针。
scoped_array使用方法:
scoped_array和scoped_ptr设计思想相同,使用方法也基本一致,如下:
scoped_array<int> pIntArray(new int[10]);
使用时需要注意的是:scoped_array
不会对数组范围进行检查,且不能通过数组名+偏移的方式进行获取。
但可以按照以下方式使用:
pIntArray[0]=100; pIntArray[1]=200; 1.5 shared_ptr
shared_ptr
已经被引入C++标准库中,功能强大,可以像普通指针那样使用,它是引用计数型指针,可以被任意的复制和拷贝。同时shared_ptr
可以被用作容器元素。
可以说shared_ptr
是C++历史上实现智能指针算法中最杰出的代表作。
shared_ptr使用方法:
shared_ptr指针是最接近原始指针的。他比auto_ptr
和scoped_ptr
应用范围更广,几乎可以百分之百避免程序中的内存泄露,但是使用却又像auto_ptr
和scoped_ptr一样简单。
shared_ptr
是线程安全的,可以由多个线程进行读取。
使用方式如下:
int main() { //定义一个指针对象 shared_ptr<int> pInt(new int); //对指针进行赋值 *pInt = 100; cout<<*pInt<<endl; //调用shared_ptr重载方法 shared_ptr<int> pInt_cp = pInt; cout<<*pInt_cp<<endl; pInt.reset(); assert(!pInt); return 0; }
如上代码所示shared_ptr
构造函数中依旧使用new的方法创建一个对象,但这个远远不够,shared_ptr提供make_shared
方法来创建一个共享指针对象,
方式如下:
int main() { shared_ptr<string> pStr= make_shared<string>("hello world"); cout<<*pStr<<endl; shared_ptr<vector<int> > pVec = make_shared<vector<int> >(10,2); cout<<pVec->size()<<endl; return 0; }
代码输出结果为:
hello world
10
shared_ptr高级用法;
shared_ptr
可以保存任意类型指针,可以理解成是改指针是泛型的。
shared_ptr<void *>退出作用域后调用回调函数,如下:
void fun(void *p){} shared_ptr<void *> p((void *0),fun);
除此之外,shared_ptr
还有其它很多高级用法,如:延时释放、包装成员函数等,感兴趣的话可以自行研究。
1.6 shared_array
shared_array
功能和shared_ptr
类似,根本区别是包装了new[]操作符,可以指向数组,知道引用计数为0时才会进行释放。
shared_array使用方法:
shared_array
是shared_ptr
和scoped_array
的结合体。
使用方法如下所示:
int main() { int *p = new int[100]; shared_array<int> sp(p); shared_array<int> sp1=sp; sp[0]=10; return 0; }
1.7 weak_ptr弱指针
weak_ptr
不具备普通指针的行为,需要和shared_ptr
配合使用。主要用于协助shared_ptr
工作,观测资源的使用情况。
weak_ptr使用方法:
weak_ptr
和shared_ptr
共用可以通过shared_ptr
或者weak_ptr对象构造,使用时不会产生引用计数增加,析构时也不会导致引用计数的减少。可以使用use_count查看引用计数,也可以使用其等效的方法expired(),如果引用计数为0则表示观测的对已经不存在了。代码示例如下:
int main() { shared_ptr<int> p(new int(100)); cout<<p.use_count()<<endl; weak_ptr<int> wp(p); cout<<wp.use_count()<<endl; p.reset(); if(!wp.expired()) { shared_ptr<int> p1=wp.lock(); *p1 = 1000; cout<<wp.use_count()<<endl; } return 0; }
2 总结
如上,介绍了boost
库提供的几种智能指针的方法、定义和使用,实际编码时可以根据使用场景使用不同的指针,这里尤其要推的是shared_ptr,
使用它几乎可以解决我们遇到的所有使用场景。当然boost还提供了一种侵入式智能指针,但是因为其使用要求严格,官方已经不再推荐使用,所以,本文也没有进行介绍。
到此这篇关于C++内存管理介绍的文章就介绍到这了,更多相关C++内存管理内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
最新评论