内存管理一直是令C++程序员最头疼的工作,C++继承了C那高效而又灵活的指针,使用起来稍微不小心就会导致内存泄露、野指针、越界访问等访问。虽然C++标准提供了只能指针std::auto_ptr,但是并没有解决所有问题。boost的smart_ptr库是对C++98标准的绝佳补充。它提供了六种智能指针,包括scoped_ptr、scoped_array、shared_ptr、shared_array、week_ptr、instrusive_ptr(不建议使用)。现在我们就学习一下这几种智能指针的使用方法和注意事项:

#include<boost/smart_ptr.hpp>
#include<boost/smart_ptr/scoped_ptr.hpp>
#include<boost/make_shared.hpp>
#include<boost/enable_shared_from_this.hpp>
#include<string>
#include<vector>
#include<cstdio>
using namespace std;
using namespace boost;
struct posix_file
{
posix_file(const char* file_name)
{
cout<<"open file:"<<file_name<<endl;
}
~posix_file()
{
cout<<"close file"<<endl;
}
};
void any_func(void* p)
{
cout<<"some operate"<<endl;
}
class self_shared : public enable_shared_from_this<self_shared>
{
public:
self_shared(int n):x(n){}
int x;
void print()
{
cout<<"self_shared:"<<x<<endl;
}
};
void ptr_test()
{
/*scoped_ptr*/
scoped_ptr<string> sp(new string("text"));
cout<<*sp<<endl;
cout<<sp->size()<<endl;
//delete sp; 不需要delete
//scoped_ptr<string> sp1(sp); 不允许,拷贝构造函数为私有
//scoped_ptr<string> sp2 = sp; 不允许,赋值函数为私有
//sp++; //错误,未定义++操作
scoped_ptr<int> p(new int);
if(p) //在bool语境中测试指针是否有效
{
*p=; //可以向普通指针一样使用解引用操作符*
cout<<*p<<endl;
}
p.reset(); //reset()置空scoped_ptr
if(p==)
{
cout<<"该指针为空"<<endl;
}
if(!p) //在bool语境中测试,可以用!操作符
{
cout<<"该指针为空"<<endl;
}
//将在离开作用域是自动析构,从而关闭文件释放资源
scoped_ptr<posix_file> fp(new posix_file("a.txt"));
/*auto_ptr 和 scoped_ptr 区别*/
auto_ptr<int> ap(new int()); //一个int的自动指针
scoped_ptr<int> sp3(ap); //从 auto_ptr 获得原始指针
if(ap.get()==) //原auto_ptr不再拥有指针
{
cout<<"该指针为空"<<endl;
}
ap.reset(new int()); //auto_ptr 拥有新的指针
cout<<*ap<<","<<*sp3<<endl; auto_ptr<int> ap2;
ap2 = ap; //ap2从ap获得原始指针,发生所有权转移
if(ap.get()==) cout<<"该指针为空"<<endl; //ap不再拥有指针
scoped_ptr<int> sp2;
//sp2 = sp; //赋值操作,无法编译通过 /*scoped_array*/
/*构造函数接受的指针p必须是new[]的结果,而不是new表达式的结果;*/
/*没有*和->操作符重载,因为scoped_array持有的不是一个普通的指针*/
/*析构函数使用delete[]释放资源,而不是delete*/
/*提供operator[]操作符重载,可以向普通数组一样用下标访问元素*/
/*没用begin()和end()等类似容器的迭代器操作函数*/
/*不能拷贝不能赋值*/
scoped_array<int> sa(new int[]); //包装动态数组
sa[] = ; /*调用[]重载函数 scoped_array 不提供数组索引的范围检查*/
//*(sa+1) = 20; 错误用法
int* arr = new int[]; //一个整数的动态数组
scoped_array<int> sa1(arr); //scoped_array 对象代理原始动态数组
fill_n(&sa1[],,); //可以使用标准库算法赋值数据
sa1[] = sa1[] + sa1[]; //使用起来像普通数组
/*不建议使用scoped_array*/ /*shared_ptr*/
/*shared_ptr是一个最像指针的“智能指针”,是boost.smart_ptr库中最有价值,最重要的组成部分*/
/*shared_ptr与scoped_ptr一样包装了new操作符在堆上分配的动态对象,它实现的是引用计数型的智能指针,可以自由的拷贝和赋值,可以安全的放在标准容器中*/
shared_ptr<int> spi(new int); //一个int的shared_ptr
if(!spi) cout<<"该指针为空"<<endl; //在bool语境中隐式转换为bool值
*spi=; //使用解引用操作符*
shared_ptr<string> sps(new string("smart"));
cout<<"该字符串长度:"<<sps->size()<<endl; //使用箭头操作符->
shared_ptr<int> spi1(new int());
if(spi1.unique()) cout<<"是该指针的唯一持有者"<<endl;
shared_ptr<int> spi2 = spi1; //调用拷贝构造函数
//两个shared_ptr相等,指向同一个对象,引用计数为2
cout<<"spi1:"<<spi1.use_count()<<",spi2:"<<spi2.use_count()<<endl;
shared_ptr<int> spi3 = spi2;
cout<<"spi1:"<<spi1.use_count()<<",spi2:"<<spi2.use_count()<<",spi3:"<<spi3.use_count()<<endl;
*spi3=;
cout<<"*spi1="<<*spi1<<",*spi2="<<*spi2<<"*spi3="<<*spi3<<endl;
spi3.reset(); //停止shared_ptr的使用
cout<<"spi1:"<<spi1.use_count()<<",spi2:"<<spi2.use_count()<<",spi3:"<<spi3.use_count()<<endl;
if(!spi3) cout<<"该指针为空"<<endl;
/*shared_ptr工厂方法*/
shared_ptr<string> sps1 = make_shared<string>("make_shared");
shared_ptr<vector<int> > spv = make_shared<vector<int> >(,);
cout<<"spv的大小:"<<spv->size()<<endl;
cout<<(*spv)[]<<endl;
/*shared_ptr应用与标准容器*/
typedef vector<shared_ptr<int> > vs;
vs v();
int i=;
for(vs::iterator pos = v.begin();pos!=v.end();++pos)
{
(*pos) = make_shared<int> (++i);
cout<<**pos<<endl; //此处两次解引用,先获得shared_ptr,在获得其内的值
}
shared_ptr<int> pp = v[];
*pp = ;
cout<<*v[]<<endl;
shared_ptr<FILE> fp1(fopen("./1.txt","r"),fclose); //带有删除器的shared_ptr,析构的时候调用fclose关闭内部的指针
/*shared_ptr<void>*/
shared_ptr<void> vp((void*),any_func); //容纳空指针,定制删除器 /*shared_array*/
/*shared_array构造函数接受的指针p必须是new[]的结果,而不能是new表达式的结果*/
/*shared_array提供operator[]操作符重载,可以像普通数组一样访问元素*/
/*没有*和->操作符重载,因为shared_array持有的不是一个普通指针*/
/*析构函数使用delete[]释放资源,而不是delete*/
int* ip = new int[];
shared_array<int> sar(ip);
shared_array<int> sar1 = sar;
sar[]=; //shared_array不提供数组索引的范围检查
cout<<"sa[0]="<<sar[]<<",sar1[0]="<<sar1[]<<endl;
/*shared_array可以用shared_ptr<std::vector>或者std::vector<shared_ptr>来代替*/ /*week_ptr*/
/*weak_ptr是配合shared_ptr而引入的一种智能指针,没有重载operator*和->*/
/*weak_ptr充当一个观察者,观察指针的引用计数,在构造和析构的时不会引起引用计数的变化*/
shared_ptr<int> spp(new int());
cout<<"该指针的引用计数:"<<spp.use_count()<<endl;
weak_ptr<int> wp(spp);          //从shared_ptr创建weak_ptr
cout<<"该指针的引用计数:"<<wp.use_count()<<endl;
if(!wp.expired())          //判断week_ptr观察的对象是否失效
{
shared_ptr<int> spp1 = wp.lock(); //获得一个shared_ptr
*spp1 = ;
cout<<"该指针的引用计数:"<<wp.use_count()<<endl;
}
cout<<"该指针的引用计数:"<<wp.use_count()<<endl;
wp.reset();
//if(!wp) cout<<"该指针无效"<<endl; 没有重载!操作符
if(wp.expired()) cout<<"该指针无效"<<endl;
if(!wp.lock()) cout<<"获取指针失败"<<endl;
/*week_ptr的的一个重要用途就是获得this指针的shared_ptr,使对象自己能够生产shared_ptr管理自己*/
shared_ptr<self_shared> ssp = make_shared<self_shared>();
ssp->print();
shared_ptr<self_shared> ssp1 = ssp->shared_from_this();
ssp1->x=;
ssp1->print();
//警告:不能从一个普通的对象(非shared_ptr)使用shared_from_this()获取shared_ptr,例如:
//self_shared ss;
//shared_ptr<self_shared> ssp3 = ss.shared_from_this();
/*以上语法上没问题,可以编译通过,但在运行时导致shared_ptr析构时企图删除一个栈上分配的对象,发生未定义行为*/ }

  pool库是Boost程序库在内存管理方面提供的另一个有用的工具,它实现了高效的内存池,用于管理内存资源。pool提供了pool、object_pool、singleton_pool、pool_alloc四种形式的内存池。

struct demo_class
{
public:
int a,b,c;
demo_class(int x=,int y=,int z=) : a(x),b(y),c(z){}
};
typedef singleton_pool<demo_class,sizeof(int)> sp1; //第一个参数仅仅作为标记,第二个参数每次分配的内存块大小
void pool_test()
{
/*boost.pool库基于简单分隔存储思想实现了一个快速紧凑的内存池库,
* 不仅能够管理大量的对象的分配/释放小对象很有效,而且不需要delete
* pool库包括四个组成部分:最简单的pool,分配类实例的 object_pool,
* 单件内存池singleton_pool和可用标准库pool_alloc*/
pool<> p1(sizeof(int)); //使用默认分配器分配一个可分配的int的内存池 sizeof(int)为一次欲分配的内存块大小
int * p = (int*)p1.malloc(); //需要把void*转换为需要的类型
if(p1.is_from(p)) cout<<"是从该pool分配的内存"<<endl;
p1.free(p); //释放内存池分配的内存快
for(int i=;i<;i++) //连续分配大量的内存
{
p1.ordered_malloc(); //该函数分配的同时合并空闲快链表
} /*object_pool使用于类实例的内存池,它的功能与pool类似,但在析构时对所有已经分配的内存快调用析构函数*/
object_pool<demo_class> p2; //对象对象内存池 demo_class* dp = (demo_class*)p1.malloc();
if(p2.is_from(dp)) cout<<"从该内存池分配的内存"<<endl;
//p指向的内存未经过初始化
cout<<dp->a<<","<<dp->b<<","<<dp->c<<endl; dp = p2.construct(,,); //构造一个对象,可以传递参数
cout<<dp->a<<","<<dp->b<<","<<dp->c<<endl;
object_pool<string> pls; //定义一个分配string对象的内存池
for(int i=;i<;i++) //连续分配大量的string对象
{
string * ps = pls.construct("hello object_pool");
cout<<*ps<<endl;
}
/*singleton_pool是一个单件内存池,不需要声明singleton_pool实例,直接用::来调用静态成员函数*/
int * pi1 = (int*) sp1::malloc();
if(sp1::is_from(pi1)) cout<<"是该内存池分配的内存"<<endl;
sp1::release_memory(); /*pool_alloc提供了两个可以用于标准容器模板参数的内存分配器,
* 分别是pool_alloc和fast_pool_allocator,除了有特别的需求,
* 我们应该总是使用STL实现自带的内存分配器,使用pool_alloc需要经过仔细的测试,以保证它与容器共同工作
* */
vector<int,pool_allocator<int> > v;
v.push_back();
cout<<v.size()<<v[]<<endl;
}

boost之内存管理的更多相关文章

  1. boost的内存管理

    smart_ptr raii ( Resource Acquisition Is Initialization ) 智能指针系列的都统称为smart_ptr.包含c++98标准的auto_ptr 智能 ...

  2. (六)boost库之内存管理shared_ptr

    (六)boost库之内存管理shared_ptr 1.shared_ptr的基本用法 boost::shared_ptr<int> sp(new int(10)); //一个指向整数的sh ...

  3. Object-C内存管理的理解总结

    今天看到了OC的内存管理这块,觉得很亲切. 自己的习惯是尽量自己掌控程序的空间和时间,有点强迫症的感觉.用C和C++做项目的时候,时时刻刻都在操心这new和delete的配对使用和计数,学习stl和b ...

  4. [基础] C++与JAVA的内存管理

    在内存管理上(总之一句话——以后C++工程,一定要用智能指针!) 1.同是new一个对象,C++一定得手动delete掉,而且得时刻记住能delete的最早时间(避免使用空指针).JAVA可以存活于作 ...

  5. C++内存管理学习笔记(5)

    /****************************************************************/ /*            学习是合作和分享式的! /* Auth ...

  6. STL内存管理

    1. 概述 STL Allocator是STL的内存管理器,也是最低调的部分之一,你可能使用了3年stl,但却不知其为何物. STL标准如下介绍Allocator the STL includes s ...

  7. C++内存管理变革(6):通用型垃圾回收器 - ScopeAlloc

    本文已经迁移到:http://cpp.winxgui.com/cn:a-general-gc-allocator-scopealloc C++内存管理变革(6):通用型垃圾回收器 - ScopeAll ...

  8. C++中的垃圾回收和内存管理

    最开始的时候看到了许式伟的内存管理变革系列,看到性能测试结果的时候,觉得这个实现很不错,没有深入研究其实现.现在想把这个用到自己的一个项目中来,在linux下编译存在一些问题,所以打算深入研究一下. ...

  9. 【cocos2d-x 3.x 学习笔记】对象内存管理

    内存管理 内存管理一直是一个不易处理的问题.开发人员必须考虑分配回收的方式和时机,针对堆和栈做不同的优化处理,等等.内存管理的核心是动态分配的对象必须保证在使用完成后有效地释放内存,即管理对象的生命周 ...

随机推荐

  1. HDU1300 Pearls(可斜率优化)

    +)*= +)*= .总共需要的花费是150+=++)*= .在两组数据看来.珍珠都买了高品质的了,而且花费也少了!问题是怎么样能花费最少买珍珠! Add:合并肯定是相邻的合并.比如啊a<b&l ...

  2. Windows7 SP1 64bit配置IIS7.5和ASP.NET4

    一.安装前的环境 1. Windows7 SP1 64bit: 2. 在安装IIS7.5之前,安装了Visual Studio 2010或.NET Framework4: 二.安装IIS7.5 1.  ...

  3. Python Logger使用

    1. 单文件的logging配置 import logging logging.basicConfig(level=logging.DEBUG, format='%(asctime)s %(filen ...

  4. 第2本MATLAB书

    前面看的<DSP using MATLAB>后面还有两章,其内容太难了,看不下去,暂时放放: 因为工作中需要MATLAB和电磁场的相关知识,从网上找了本 初步翻了翻,里面有代码有图片,英文 ...

  5. 字符串循环右移N位

    给一个长度为n的字符串,把这个字符串循环右移N位(0<N<n),要求只用O(1)的额外空间和O(N)时间,有些什么方法 一开始想到的是先保存temp=s[0],在左起第N个移到s[0]的位 ...

  6. Linux学习系列之Nginx调优实战

    Nginx配置文件性能微调 全局的配置 user www-data; pid /var/run/nginx.pid; worker_processes auto; worker_rlimit_nofi ...

  7. 彻底解密C++宽字符(二)

    彻底解密C++宽字符(二) 转:http://club.topsage.com/thread-2227977-1-1.html 4.利用codecvt和use_facet转换 locale和facet ...

  8. Linux下搭建企业共享目录方案之------samba

    Samba是在Linux和UNIX系统上实现SMB协议的一个免费软件,由服务器及客户端程序构成.SMB(Server Messages Block,信息服务块)是一种在局域网上共享文件和打印机的一种通 ...

  9. solr精确查询,查询关键字分词后,指定满足匹配所有

    一.solr查询,查询配置了查询分词器的字段,默认会对查询关键字做分词处理 1.如查询关键字F1501ZY000011,使用solr7自带的中文分词器,默认会分词为:f,1501,zy,000011 ...

  10. Xenu Link Sleuth 简单好用的链接测试工具 使用说明

    XenuLink Sleuth 名词介绍 “Xenu链接检测侦探”是被广泛使用的死链接检测工具.可以检测到网页中的普通链接.图片.框架.插件.背景.样式表.脚本和java程序中的链接. 那么神马时候出 ...