Boost基础学习

来源:互联网 发布:老人去世无人知 编辑:程序博客网 时间:2024/06/03 07:28

1  Boost的安装及配置

1.1 在C/C++中添加include路径


如上图所示,本地include路径为P:\SVN-corbadevelop\ext\include,将路径填入附加包含目录项。

1.2 在链接器中添加lib路径


如上图所示,本地lib路径为P:\SVN-corbadevelop\ext\lib\vc9,将路径填入附加库目录。

2  Boost库知识学习

2.1 时间和日期

Timer类是一个小型的计时器,可以测量时间流逝。提供毫秒级的计时精度和操作函数。

头文件:<boost/timer.hpp>  命名空间:usingnamespace boost;

 class timer

 {

 public:

       timer() { _start_time = std::clock(); } //clock()为起点

       void  restart() { _start_time = std::clock(); }

       double elapsed() const                 

       { return double(std::clock() -_start_time) / CLOCKS_PER_SEC; }

       double elapsed_max() const

       {

       return(double((std::numeric_limits<std::clock_t>::max)()) -double(_start_time)) / double(CLOCKS_PER_SEC);

       }

           double elapsed_min() const

       { return double(1)/double(CLOCKS_PER_SEC); }

        private:

        std::clock_t _start_time;//进程启动时的clock数

       };

Timer及时使用了标准库头文件<ctime>里的std::clock()函数,返回自进程启动以来的clock数,每秒clock数由宏CLOCKS_PER_SEC定义。

注意:

1.在timer没有定义析构函数, 这样做是正确和安全的。因为它仅有一个类型为clock_t的成员变量_start_time,故没有必要实现析构函数来特意“释放资源”(也无资源可释放)。

2.timer接口简单,轻巧好用,适用于大部分的程序计时任务。但使用时,我们必须理解elapsed_min()和elapsed_max()这两个计时精度函数的定义,它们表明了timer的能力。timer不适合高精度的时间测量任务,它的精度依赖于操作系统和编译器,难以做到跨平台。

3.timer也不适合大跨度时间段的测量,可提供的最大时间跨度只有几百个小时,如果需要天,月等的时间跨度,则应使用date_time库。

Progress_timer类是一个计时器,继承自timer,会在析构函数时自动输出时间,实现自动计时。(在函数结束时调用析构)

头文件:<boost/progress.hpp>

Progress_timer类可以在控制台上显示程序的执行进度。

头文件:<boost/progress.hpp>

使用方法:process_display pd(vector::size());

注意:由于给类也使用标准输出(cout)进行输出,与程序输出使用同一输出,如果程序也有输出操作,将会扰乱Progress_timer的输出。

2.2date_time库

使用date_time库,需加宏定义:

#define BOOST_DATA_TIME_NO_LIB或#define BOOST_ALL_NO_LIB

包含头文件:#include<boost/date_time/gregorian/gregorian.hpp>

命名空间:using namespace boost::gregorian

注:如果不希望date的缺省构造出无效日期,可以在头文件前定义宏DATE_TIME_NO_DEFAULT_CONSTRUCTOR,禁止缺省构造函数。

//progress_timer demo测试

bool p_timer_test()

{

vector<int> v(100,1);//100个1

progress_timer t;

progress_display pd(v.size());

vector<int>::iterator pos;

for(pos = v.begin();pos !=v.end();++pos)

{

//cout<<*pos<<endl;//注意!!打印输出时,会干扰process_display输出

++pd;//使用重载++来刷新进度

}

return true;

}

 

date_time 库使用枚举special_values定义特殊的时间概念位于命名空间:

pos_infin ---表示正无限

neg_infin------表示负无限

not_a_date_time-------无效时间

min_data_time------表示的最小日期1400-01-01

max_data_time--------最大日期9999-12-31

日期的处理:

date是date_time库处理的核心类使用32位整数作为内部存储,可拷贝传值,比较操作

流输入输出

date d1;///一个无效的日期对象

date d2(2010,1,1)数字构造日期

date d3(2000,Jan,1)//英文指定月份

dated4=from_string("1999-12-31")

date d4(from_string(2005/1/1))//支持拷贝构造工程函数通过/或-分割

dated3=from_undelimted_string("20011112")//支持无分割符的纯字符串

day_lock是无级别时钟他是一个工程类调用他的静态成员函数local_day()

universal_day()会返回当天日期对象分别是本地时期和utc日期

date 的5个is_xxx()函数用于检测日期是否是个特殊日期

is_infinity()是否是个无限日期

is_neg_infinity()是否是个负无限日期

is_pos_infinity().......正无限日期

is_not_a_date......无效日期

is_special()......特殊日期

date很方便的转化成字符串提供三个自由函数

to_simple_string(date d)转换成yyy-mmm-dd mmm三字符英语月份

to_iso_string(date d) YYYMMDD

to_iso_extended_string(date d)转换成yyy-mm-dd

与tm结构的转换:

to_tm(date)

date_from_tm:tm 转化为date

日期长度

日期长度是以天为单位的时长,是度量时间长度的一个标量

基本的日期长度类是date_duration 支持全序比较操作(== != > >=)也支持递增和递减

作也支持除法运算但是不能除date_duration类型,乘法取余取模则不支持

date_time 库为date_duration 定义了一个常用的typedef:day 说明了其含义一个天数的计量,为了方便计算时间长度 date_time 库还提供了monthsyears weeks 等另外三个时长类。

2.3boost智能指针

智能指针能够在推出作用域时—不管是正常流程离开还是异常离开,总调用delete来析构堆上动态分配的对象。

头文件:#include <boost/smart_ptr.hpp>

usingnamespace boost;

boost主要提供以下六种智能指针:

shared_ptr<T>

内部维护一个引用计数器来判断此指针是不是需要被释放。是boost中最常用的智能指针了。

scoped_ptr<t>

当这个指针的作用域消失之后自动释放

intrusive_ptr<T>

也维护一个引用计数器,比shared_ptr有更好的性能。但是要求T自己提供这个计数器。

weak_ptr<T>

弱指针,要和shared_ptr 结合使用

shared_array<T>

和shared_ptr相似,但是访问的是数组

scoped_array<T>

和scoped_ptr相似,但是访问的是数组

 

2.3.1 shared_ptr

shared_ptr包装了new操作符在堆上分配的动态对象,但它实现的是引用计数型的智能指针,可以被自由的靠背和赋值,当没有代码使用(引用计数为0时),它才删除被包装的动态分配对象。Shared_ptr可以应用到标准容器中,弥补了auto_ptr和scoped_ptr的不足。

测试demo:

bool Shared_ptr_test()//智能指针shared_ptr测试

{

       shared_ptr<test>T2(new test);

       cout<<"nowT2 has "<<T2.use_count()<<" object"<<endl;

       shared_ptr<test>T3 = T2;

       cout<<"nowT3 has "<<T3.use_count()<<" object"<<endl;

       T2.reset();//T2清空

       cout<<"nowT3 has "<<T3.use_count()<<" object"<<endl;

       cout<<"nowT3 unique is "<<T3.unique()<<endl;//此时T3只有1个对象,unique返回true

       T3.reset();//T3对象清空

       cout<<"nowT3 has "<<T3.use_count()<<" object"<<endl;

       cout<<"nowT3 unique is "<<T3.unique()<<endl;//此时T3只有0个对象,unique返回false

       returntrue;

}


注意事项:

1,不要构造临时shared_ptr变量,可能会造成内存泄露:

function (shared_ptr<int>(new int), g( ) );  //有缺陷

可能的过程是先new int,然后调g( ),g( )发生异常,shared_ptr<int>没有创建,int内存泄露。

解决:

shared_ptr<int>p(new int());

f(p, g());  //Boost推荐写法

2,不要把一个原生指针给多个shared_ptr管理:

int* ptr = new int;

shared_ptr<int>p1(ptr);

shared_ptr<int>p2(ptr); //logic error

ptr对象被删除了2次

3,不要把this指针交给shared_ptr管理:

class Test{

public:

    void Do(){ m_sp = shared_ptr<Test>(this);  }

private:

    shared_ptr<Test> m_member_sp;

};

Test* t = new Test;

shared_ptr<Test>local_sp(t);

p->Do();

其中test构造了t,local_sp管理t;而t又交给m_sp管理。因此在释放时删除了两遍。

2.3.2 scoped_ptr

boost::scoped_ptr和auto_ptr类似,使用简单,能保证在离开作用域后能自动释放。

头文件:#include <boost/scoped_ptr.hpp>

scoped_ptr的特点:

1.不能转换所有权

boost::scoped_ptr所管理的对象生命周期仅仅局限于一个区间(该指针所在的"{}"之间),无法传到区间之外,这就意味着boost::scoped_ptr对象是不能作为函数的返回值的(std::auto_ptr可以)。

2.不能共享所有权

这点和std::auto_ptr类似。这个特点一方面使得该指针简单易用。另一方面也造成了功能的薄弱—不能用于stl的容器中。

3.不能用于管理数组对象

由于boost::scoped_ptr是通过delete来删除所管理对象的,而数组对象必须通过deletep[]来删除,因此boost::scoped_ptr是不能管理数组对象的,如果要管理数组对象需要使用boost::scoped_array类。

Demo测试:

class test

{

public:

       ~test(){cout<<"iam done"<<endl;}

       voiddo_something(){cout<<"begin..."<<endl;}

      

};

bool Smart_ptr_test()//智能指针scoped_ptr测试

{

       scoped_ptr<test>T1(new test);

       T1->do_something();

       returntrue;

}

输出结果:

 

当T1离开作用域后,自动调用析构函数释放。

2.3.3 intrusive_ptr<T>

是一种侵入式的引用计数型指针。但并不常用,因为shared_ptr可满足绝大部分需求。

2.3.4 weak_ptr<T>

weak_ptr是为shared_ptr而引入的一种智能指针,可理解为shared_ptr的助手,作为观察者,当shared_ptr失效,它也随之失效。

weak_ptr没有共享资源,它的构造不会引起指针计数器的增加,析构也不会引起指针计数器的减少。

boost::weak_ptr必须从一个boost::share_ptr或另一个boost::weak_ptr转换而来,这也说明,进行该对象的内存管理的是那个强引用的boost::share_ptr。

boost::weak_ptr只是提供了对管理对象的一个访问手段。

boost::weak_ptr除了对所管理对象的基本访问功能(通过get()函数)外,还有两个常用的功能函数:

1. expired() 用于检测所管理的对象是否已经释放;

2. lock() 用于获取所管理的对象的强引用指针。

注:weak的重要作用:

1,配合share_ptr解决不能管理循环引用的问题

class children

{

public:

~children() { std::cout<<"destroying children\n"; }

public:

boost::weak_ptr<parent>parent;

};

由于weak_ptr不更改引用计数,类似普通指针,只要把循环引用的一方使用weak_ptr,即可解除循环引用。

 

2.3.5 shared_array<T>

shared_array类似shared_ptr,他包装了new[]操作符在堆上分配动态数组,直到没有任何饮用后才释放内存。

shared_array与shared_ptr的区别如下:

1:构造函数接受的指针p必须是new[]的结果,而不能是new表达式。

2:提供operator[]操作符重载,可以像普通数组一样用下标访问元素。

3:没有*、->操作符重载,因为shared_array持有的不是一个普通指针。

4:析构函数使用delete[]释放资源,而不是delete。

2.3.6 scoped_array<T>

scoped_array与scoped_ptr区别基本不大,主要特点如下:

1,构造函数接受的指针p必须是new[]的结果,而不是new表达式的结果;

2,没有*、->操作符重载,scoped_array持有的不是一个普通指针;

3,析构函数使用delete[],而不是delete;

4,提供operator[]重载,可以像普通数组一样使用下标访问元素;

5,没有begin(),end()等类似容器迭代器操作函数。

该方法不推荐,因为scoped_array<T>功能有限,可以有vector等代替,不支持容器操作。

2.4 Pool库

Boost库的pool提供了一个内存池分配器,用于管理在一个独立的、大的分配空间里的动态内存分配。Boost库的pool主要适用于快速分配同样大小的内存块,尤其是反复分配和释放同样大小的内存块的情况。使用pool内存池主要有以下两个优点:

1. 能够有效地管理许多小型对象的分配和释放工作,避免了自己去管理内存而产生的内存碎片和效率低下问题。

2. pool库会在内部对内存自动进行管理,避免了程序员一不小心而造成的内存泄漏问题。

pool库主要提供了四种内存池接口,分别是pool、object_pool、singleton_pool和pool_allocator(fast_pool_allocator)。

头文件:<boost/pool/pool.hpp>

2.4.1 Pool

Pool 可以像malloc()一样分配内存,退出时,除非需要,否则不必调用free();

is_from(p);检查是否已经分配内存

release_memory()释放空闲的内存,不影响已分配的内存。

purge_memory()强制释放pool内所有内存

2.4.2 object_pool

用于类实例的内存池,退出时会调用析构函数。

头文件:头文件:<boost/pool/object_pool.hpp>

Class object_pool:protectedpool;//由于是保护继承,因此object_pool的对象不能访问pool。

Demo测试:

#include<boost/pool/object_pool.hpp>  

using namespace boost;   

struct demo_class                           //一个示范用的类   

{   

public:       

   int a,b,c;       

   demo_class(int x = 1, int y = 2, int z = 3):a(x),b(y),c(z){}   

};   

int main()   

{       

   object_pool<demo_class> pl;             //对象内存池        

   demo_class *p = pl.malloc();           //分配一个原始内存块       

   assert(pl.is_from(p));       //p指向的内存未经过初始化       

   assert(p->a!=1 || p->b != 2 || p->c !=3);        

   p = pl.construct(7, 8, 9);             //构造一个对象,可以传递参数       

   assert(p->a == 7);        

   object_pool<string> pls;                //定义一个分配string对象的内存池       

   for (int i = 0; i < 10 ; ++i)           //连续分配大量string对象       

   {           

        string *ps = pls.construct("helloobject_pool");           

        cout << *ps << endl;       

   }   

}                                           //所有创建的对象在这里都被正确析构、释放内存

2.4.3 singleton_pool

singleton_pool的接口与pool完全一致,但成员函数均是静态的,因此不需要声明singleton_pool的实例 ,直接用域操作符::来调用静态成员函数。因为singleton_pool是单件,所以它的生命周期与整个程序同样长,除非手动调用release_memory()或purge_memory(),否则singleton_pool不会自动释放所占用的内存。除了这两点,singleton_pool的用法与pool完全相同。

singleton_pool<pool_tag, sizeof(int)>// 第一个Tag仅仅是用于标记不同的单件,可以是空类,甚至是声明。第二个参数RequestedSize等同于pool构造函数中的整数requested_ size,指示pool分配内存块的大小。

singleton_pool在使用时最好使用typedef来简化名称,否则会使得类型名过于冗长而难以使用。

2.4.4 pool_allocator

头文件<boost/pool/pool_alloc.hpp>

vector<int,pool_allocator<int>> v;

v.push_back(10);

cout<<v.size()<<endl;

2.5 thread

Thread库是高度可移植,支持广泛的windows和POSIX线程,不需要修改就能在操作系统上运行。

头文件:<boost/thread.hpp>

Thread需要date_time支持,因此需要加上

#defineBOOST_DATE_TIME_SOURCE

#defineBOOST_THREAD_NO_LIB

或者

#defineBOOST_ALL_NO_LIB

注:阻止link错误的方法:extern “C”void tss_cleanup_implemented(void){},该定义实现了自动tss(线程本地存储)清理功能。

vs2008线程库的配置

在附加依赖项中添加boost_tread-vc90-mt-gd-1_47.lib库,并将boost_tread-vc90-mt-gd-1_47.dll放入工程文件夹debug下。


2.5.1互斥量

Boost线程库支持两大类互斥体,包括简单互斥体(simple mutex)和递归互斥体(recursive mutex)。如果同一个线程对互斥体上了两次锁,就会发生死锁(deadlock),也就是说所有的等待解锁的线程将一直等下去。有了递归互斥体,单个 线程就可以对互斥体多次上锁,当然也必须解锁同样次数来保证其他线程可以对这个互斥体上锁。

boost::mutex:独占式互斥量,是最简单最常用的一种互斥量类型

boost::try_mutex:它是mutex的同义词,为了兼容以前的版本而提供

boost::timed_mutex:他也是独占式的互斥量,但提供超时锁定功能

boost::recursive_mutex:递归式互斥量,可以多次锁定,相应的也要多次解锁

boost::recursive_try_mutex:它是recrusive_mutex的同义词,为兼容以前版本提供

boost::recursive_timed_mutex: 递归式互斥量,基本功能与recrusive_mutex相同,但提供超时锁定功能

boost::shared_mutex:读写锁

(1)scopde_lock

测试demo:

boost::mutex io_mutex;

struct count

{

count(int id) : id(id) { }

void operator()()//重载(),当对象使用()时,会执行程序功能

{

for (int i = 0;i < 5; ++i)

{

boost::mutex::scoped_lock lock(io_mutex);

std::cout << id << ": "<< i<< std::endl;

}

}

int id;

};

int main(int argc,char* argv[])

{

boost::thread thrd1(count(1));

boost::thread thrd2(count(2));

thrd1.join();

thrd2.join();

return 0;

}

结果:


可以看到,在thrd1执行时,thrd2在等待。等到thrd1执行完后,开始thrd2

2Bind

测试demo

boost::mutex io_mutex;

void count(int id)

{

for (int i = 0;i < 10; ++i)

{

boost::mutex::scoped_lock lock(io_mutex);

std::cout << id << ": " <<i<< std::endl;

}

}

int main(int argc,char* argv[])

{

boost::thread thrd1(boost::bind(&count,1));

boost::thread thrd2(boost::bind(&count,2));

thrd1.join();

thrd2.join();

return 0;

}

 

3thread_specific_ptr

Boost线程库提供了智能指针boost::thread_specific_ptr来访问本地存储线程。每一个线程第一次使用这个智能指针的实 例时,它的初值是NULL,所以必须要先检查这个它的只是否为空,并且为它赋值。Boost线程库保证本地存储线程中保存的数据会在线程结束后被清除。

测试demo:

using namespace boost;

using namespace std;

mutex io_mu;

thread_specific_ptr<int> ptr;

struct counts1

{

counts1(int id):id(id){}

void operator()()

{

if(ptr.get() == 0)

ptr.reset(new int(0));

for (int i = 0;i<5;i++)

{

(*ptr)++;

mutex::scoped_lock lock_s(io_mu);

cout<<id<<":"<<*ptr<<endl;

}

}

int id;

};

void mutex_test()

{

thread t1(counts1(1));

thread t2(counts1(2));

t1.join();

t2.join();

}

结果:

3  函数与回调

3.1 bind

头文件:#include<boost/bind.hpp>

bind最多有十个参数,第一个可调用的对象,之后可以接最多九个参数,参数量必须与可调用对象的参数相同。点位符为_1 _2等等,位置可以随意放。点位符可以出现,也可以不出现。

成员函数:第一个参数为成员函数地址,第二个参数为对象。

成员变量:第一个参数为成员变量的地址,第二个参数为对象。

注:绑定成员函数时:

1,因为成员函数的指针不能直接调用operator(),因此,它必须被绑定到一个对象或者指针。然后才能得到this指针进而调用成员函数。在bind时,需要用一个占位符的位置,提供一个类的实例、引用或者指针,通过对象作为第一个参数来调用成员函数。

2,必须在成员函数前加取地址符&,表明这是一个函数指针。绑定变量时也一样。

3.2 function

头文件:#include<boost/function.hpp>

测试demo:bind与function合用

using namespace boost;

using namespace std;

struct demo

int print(int a){return a;}

int operator()(int a){return a;}

};

int f(int a)

{return a;}

void function_bind()

{

function<int(int)> fuc;

fuc = f;

cout<<fuc(3)<<endl;

demo dm;

function<int(int)> fuc2;

fuc2 = bind(&demo::print,&dm,_1);//成员函数前必须加去地址符&,dm是提供的类的对象的引用。

cout<<fuc2(34)<<endl;

function<int(demo&,int)> fuc3;//在定义时,形参定义demo类的指针,在绑定时,可用占位符代替

fuc3 = bind(&demo::print,_1,_2);//也可以预留占位符_1,在调用fun3时,将类的对象、实例或引用填入

cout<<fuc3(dm,56)<<endl;

}

结果:


3.3 signals2

头文件:#include<boost/signals2.hpp>

connect() disconnect()连接或断开信号与插槽。

empty() num_slots()返回是否为空,返回插槽数量。

disconnect_all_slots()断开所有信号与插槽的连接。

combiner() set_combiner()用于获取和设置合并器对象

1  Boost的安装及配置

1.1 在C/C++中添加include路径


如上图所示,本地include路径为P:\SVN-corbadevelop\ext\include,将路径填入附加包含目录项。

1.2 在链接器中添加lib路径

如上图所示,本地lib路径为P:\SVN-corbadevelop\ext\lib\vc9,将路径填入附加库目录。

2  Boost库知识学习

2.1 时间和日期

Timer类是一个小型的计时器,可以测量时间流逝。提供毫秒级的计时精度和操作函数。

头文件:<boost/timer.hpp>  命名空间:usingnamespace boost;

 class timer

 {

 public:

       timer() { _start_time = std::clock(); } //clock()为起点

       void  restart() { _start_time = std::clock(); }

       double elapsed() const                 

       { return double(std::clock() -_start_time) / CLOCKS_PER_SEC; }

       double elapsed_max() const

       {

       return(double((std::numeric_limits<std::clock_t>::max)()) -double(_start_time)) / double(CLOCKS_PER_SEC);

       }

           double elapsed_min() const

       { return double(1)/double(CLOCKS_PER_SEC); }

        private:

        std::clock_t _start_time;//进程启动时的clock数

       };

Timer及时使用了标准库头文件<ctime>里的std::clock()函数,返回自进程启动以来的clock数,每秒clock数由宏CLOCKS_PER_SEC定义。

注意:

1.在timer没有定义析构函数, 这样做是正确和安全的。因为它仅有一个类型为clock_t的成员变量_start_time,故没有必要实现析构函数来特意“释放资源”(也无资源可释放)。

2.timer接口简单,轻巧好用,适用于大部分的程序计时任务。但使用时,我们必须理解elapsed_min()和elapsed_max()这两个计时精度函数的定义,它们表明了timer的能力。timer不适合高精度的时间测量任务,它的精度依赖于操作系统和编译器,难以做到跨平台。

3.timer也不适合大跨度时间段的测量,可提供的最大时间跨度只有几百个小时,如果需要天,月等的时间跨度,则应使用date_time库。

Progress_timer类是一个计时器,继承自timer,会在析构函数时自动输出时间,实现自动计时。(在函数结束时调用析构)

头文件:<boost/progress.hpp>

Progress_timer类可以在控制台上显示程序的执行进度。

头文件:<boost/progress.hpp>

使用方法:process_display pd(vector::size());

注意:由于给类也使用标准输出(cout)进行输出,与程序输出使用同一输出,如果程序也有输出操作,将会扰乱Progress_timer的输出。

2.2date_time库

使用date_time库,需加宏定义:

#define BOOST_DATA_TIME_NO_LIB或#define BOOST_ALL_NO_LIB

包含头文件:#include<boost/date_time/gregorian/gregorian.hpp>

命名空间:using namespace boost::gregorian

注:如果不希望date的缺省构造出无效日期,可以在头文件前定义宏DATE_TIME_NO_DEFAULT_CONSTRUCTOR,禁止缺省构造函数。

//progress_timer demo测试

bool p_timer_test()

{

vector<int> v(100,1);//100个1

progress_timer t;

progress_display pd(v.size());

vector<int>::iterator pos;

for(pos = v.begin();pos !=v.end();++pos)

{

//cout<<*pos<<endl;//注意!!打印输出时,会干扰process_display输出

++pd;//使用重载++来刷新进度

}

return true;

}

 

date_time 库使用枚举special_values定义特殊的时间概念位于命名空间:

pos_infin ---表示正无限

neg_infin------表示负无限

not_a_date_time-------无效时间

min_data_time------表示的最小日期1400-01-01

max_data_time--------最大日期9999-12-31

日期的处理:

date是date_time库处理的核心类使用32位整数作为内部存储,可拷贝传值,比较操作

流输入输出

date d1;///一个无效的日期对象

date d2(2010,1,1)数字构造日期

date d3(2000,Jan,1)//英文指定月份

dated4=from_string("1999-12-31")

date d4(from_string(2005/1/1))//支持拷贝构造工程函数通过/或-分割

dated3=from_undelimted_string("20011112")//支持无分割符的纯字符串

day_lock是无级别时钟他是一个工程类调用他的静态成员函数local_day()

universal_day()会返回当天日期对象分别是本地时期和utc日期

date 的5个is_xxx()函数用于检测日期是否是个特殊日期

is_infinity()是否是个无限日期

is_neg_infinity()是否是个负无限日期

is_pos_infinity().......正无限日期

is_not_a_date......无效日期

is_special()......特殊日期

date很方便的转化成字符串提供三个自由函数

to_simple_string(date d)转换成yyy-mmm-dd mmm三字符英语月份

to_iso_string(date d) YYYMMDD

to_iso_extended_string(date d)转换成yyy-mm-dd

与tm结构的转换:

to_tm(date)

date_from_tm:tm 转化为date

日期长度

日期长度是以天为单位的时长,是度量时间长度的一个标量

基本的日期长度类是date_duration 支持全序比较操作(== != > >=)也支持递增和递减

作也支持除法运算但是不能除date_duration类型,乘法取余取模则不支持

date_time 库为date_duration 定义了一个常用的typedef:day 说明了其含义一个天数的计量,为了方便计算时间长度 date_time 库还提供了monthsyears weeks 等另外三个时长类。

2.3boost智能指针

智能指针能够在推出作用域时—不管是正常流程离开还是异常离开,总调用delete来析构堆上动态分配的对象。

头文件:#include <boost/smart_ptr.hpp>

usingnamespace boost;

boost主要提供以下六种智能指针:

shared_ptr<T>

内部维护一个引用计数器来判断此指针是不是需要被释放。是boost中最常用的智能指针了。

scoped_ptr<t>

当这个指针的作用域消失之后自动释放

intrusive_ptr<T>

也维护一个引用计数器,比shared_ptr有更好的性能。但是要求T自己提供这个计数器。

weak_ptr<T>

弱指针,要和shared_ptr 结合使用

shared_array<T>

和shared_ptr相似,但是访问的是数组

scoped_array<T>

和scoped_ptr相似,但是访问的是数组

 

2.3.1 shared_ptr

shared_ptr包装了new操作符在堆上分配的动态对象,但它实现的是引用计数型的智能指针,可以被自由的靠背和赋值,当没有代码使用(引用计数为0时),它才删除被包装的动态分配对象。Shared_ptr可以应用到标准容器中,弥补了auto_ptr和scoped_ptr的不足。

测试demo:

bool Shared_ptr_test()//智能指针shared_ptr测试

{

       shared_ptr<test>T2(new test);

       cout<<"nowT2 has "<<T2.use_count()<<" object"<<endl;

       shared_ptr<test>T3 = T2;

       cout<<"nowT3 has "<<T3.use_count()<<" object"<<endl;

       T2.reset();//T2清空

       cout<<"nowT3 has "<<T3.use_count()<<" object"<<endl;

       cout<<"nowT3 unique is "<<T3.unique()<<endl;//此时T3只有1个对象,unique返回true

       T3.reset();//T3对象清空

       cout<<"nowT3 has "<<T3.use_count()<<" object"<<endl;

       cout<<"nowT3 unique is "<<T3.unique()<<endl;//此时T3只有0个对象,unique返回false

       returntrue;

}

注意事项:

1,不要构造临时shared_ptr变量,可能会造成内存泄露:

function (shared_ptr<int>(new int), g( ) );  //有缺陷

可能的过程是先new int,然后调g( ),g( )发生异常,shared_ptr<int>没有创建,int内存泄露。

解决:

shared_ptr<int>p(new int());

f(p, g());  //Boost推荐写法

2,不要把一个原生指针给多个shared_ptr管理:

int* ptr = new int;

shared_ptr<int>p1(ptr);

shared_ptr<int>p2(ptr); //logic error

ptr对象被删除了2次

3,不要把this指针交给shared_ptr管理:

class Test{

public:

    void Do(){ m_sp = shared_ptr<Test>(this);  }

private:

    shared_ptr<Test> m_member_sp;

};

Test* t = new Test;

shared_ptr<Test>local_sp(t);

p->Do();

其中test构造了t,local_sp管理t;而t又交给m_sp管理。因此在释放时删除了两遍。

2.3.2 scoped_ptr

boost::scoped_ptr和auto_ptr类似,使用简单,能保证在离开作用域后能自动释放。

头文件:#include <boost/scoped_ptr.hpp>

scoped_ptr的特点:

1.不能转换所有权

boost::scoped_ptr所管理的对象生命周期仅仅局限于一个区间(该指针所在的"{}"之间),无法传到区间之外,这就意味着boost::scoped_ptr对象是不能作为函数的返回值的(std::auto_ptr可以)。

2.不能共享所有权

这点和std::auto_ptr类似。这个特点一方面使得该指针简单易用。另一方面也造成了功能的薄弱—不能用于stl的容器中。

3.不能用于管理数组对象

由于boost::scoped_ptr是通过delete来删除所管理对象的,而数组对象必须通过deletep[]来删除,因此boost::scoped_ptr是不能管理数组对象的,如果要管理数组对象需要使用boost::scoped_array类。

Demo测试:

class test

{

public:

       ~test(){cout<<"iam done"<<endl;}

       voiddo_something(){cout<<"begin..."<<endl;}

      

};

bool Smart_ptr_test()//智能指针scoped_ptr测试

{

       scoped_ptr<test>T1(new test);

       T1->do_something();

       returntrue;

}

输出结果:

 

当T1离开作用域后,自动调用析构函数释放。

2.3.3 intrusive_ptr<T>

是一种侵入式的引用计数型指针。但并不常用,因为shared_ptr可满足绝大部分需求。

2.3.4 weak_ptr<T>

weak_ptr是为shared_ptr而引入的一种智能指针,可理解为shared_ptr的助手,作为观察者,当shared_ptr失效,它也随之失效。

weak_ptr没有共享资源,它的构造不会引起指针计数器的增加,析构也不会引起指针计数器的减少。

boost::weak_ptr必须从一个boost::share_ptr或另一个boost::weak_ptr转换而来,这也说明,进行该对象的内存管理的是那个强引用的boost::share_ptr。

boost::weak_ptr只是提供了对管理对象的一个访问手段。

boost::weak_ptr除了对所管理对象的基本访问功能(通过get()函数)外,还有两个常用的功能函数:

1. expired() 用于检测所管理的对象是否已经释放;

2. lock() 用于获取所管理的对象的强引用指针。

注:weak的重要作用:

1,配合share_ptr解决不能管理循环引用的问题

class children

{

public:

~children() { std::cout<<"destroying children\n"; }

public:

boost::weak_ptr<parent>parent;

};

由于weak_ptr不更改引用计数,类似普通指针,只要把循环引用的一方使用weak_ptr,即可解除循环引用。

 

2.3.5 shared_array<T>

shared_array类似shared_ptr,他包装了new[]操作符在堆上分配动态数组,直到没有任何饮用后才释放内存。

shared_array与shared_ptr的区别如下:

1:构造函数接受的指针p必须是new[]的结果,而不能是new表达式。

2:提供operator[]操作符重载,可以像普通数组一样用下标访问元素。

3:没有*、->操作符重载,因为shared_array持有的不是一个普通指针。

4:析构函数使用delete[]释放资源,而不是delete。

2.3.6 scoped_array<T>

scoped_array与scoped_ptr区别基本不大,主要特点如下:

1,构造函数接受的指针p必须是new[]的结果,而不是new表达式的结果;

2,没有*、->操作符重载,scoped_array持有的不是一个普通指针;

3,析构函数使用delete[],而不是delete;

4,提供operator[]重载,可以像普通数组一样使用下标访问元素;

5,没有begin(),end()等类似容器迭代器操作函数。

该方法不推荐,因为scoped_array<T>功能有限,可以有vector等代替,不支持容器操作。

2.4 Pool库

Boost库的pool提供了一个内存池分配器,用于管理在一个独立的、大的分配空间里的动态内存分配。Boost库的pool主要适用于快速分配同样大小的内存块,尤其是反复分配和释放同样大小的内存块的情况。使用pool内存池主要有以下两个优点:

1. 能够有效地管理许多小型对象的分配和释放工作,避免了自己去管理内存而产生的内存碎片和效率低下问题。

2. pool库会在内部对内存自动进行管理,避免了程序员一不小心而造成的内存泄漏问题。

pool库主要提供了四种内存池接口,分别是pool、object_pool、singleton_pool和pool_allocator(fast_pool_allocator)。

头文件:<boost/pool/pool.hpp>

2.4.1 Pool

Pool 可以像malloc()一样分配内存,退出时,除非需要,否则不必调用free();

is_from(p);检查是否已经分配内存

release_memory()释放空闲的内存,不影响已分配的内存。

purge_memory()强制释放pool内所有内存

2.4.2 object_pool

用于类实例的内存池,退出时会调用析构函数。

头文件:头文件:<boost/pool/object_pool.hpp>

Class object_pool:protectedpool;//由于是保护继承,因此object_pool的对象不能访问pool。

Demo测试:

#include<boost/pool/object_pool.hpp>  

using namespace boost;   

struct demo_class                           //一个示范用的类   

{   

public:       

   int a,b,c;       

   demo_class(int x = 1, int y = 2, int z = 3):a(x),b(y),c(z){}   

};   

int main()   

{       

   object_pool<demo_class> pl;             //对象内存池        

   demo_class *p = pl.malloc();           //分配一个原始内存块       

   assert(pl.is_from(p));       //p指向的内存未经过初始化       

   assert(p->a!=1 || p->b != 2 || p->c !=3);        

   p = pl.construct(7, 8, 9);             //构造一个对象,可以传递参数       

   assert(p->a == 7);        

   object_pool<string> pls;                //定义一个分配string对象的内存池       

   for (int i = 0; i < 10 ; ++i)           //连续分配大量string对象       

   {           

        string *ps = pls.construct("helloobject_pool");           

        cout << *ps << endl;       

   }   

}                                           //所有创建的对象在这里都被正确析构、释放内存

2.4.3 singleton_pool

singleton_pool的接口与pool完全一致,但成员函数均是静态的,因此不需要声明singleton_pool的实例 ,直接用域操作符::来调用静态成员函数。因为singleton_pool是单件,所以它的生命周期与整个程序同样长,除非手动调用release_memory()或purge_memory(),否则singleton_pool不会自动释放所占用的内存。除了这两点,singleton_pool的用法与pool完全相同。

singleton_pool<pool_tag, sizeof(int)>// 第一个Tag仅仅是用于标记不同的单件,可以是空类,甚至是声明。第二个参数RequestedSize等同于pool构造函数中的整数requested_ size,指示pool分配内存块的大小。

singleton_pool在使用时最好使用typedef来简化名称,否则会使得类型名过于冗长而难以使用。

2.4.4 pool_allocator

头文件<boost/pool/pool_alloc.hpp>

vector<int,pool_allocator<int>> v;

v.push_back(10);

cout<<v.size()<<endl;

2.5 thread

Thread库是高度可移植,支持广泛的windows和POSIX线程,不需要修改就能在操作系统上运行。

头文件:<boost/thread.hpp>

Thread需要date_time支持,因此需要加上

#defineBOOST_DATE_TIME_SOURCE

#defineBOOST_THREAD_NO_LIB

或者

#defineBOOST_ALL_NO_LIB

注:阻止link错误的方法:extern “C”void tss_cleanup_implemented(void){},该定义实现了自动tss(线程本地存储)清理功能。

vs2008线程库的配置

在附加依赖项中添加boost_tread-vc90-mt-gd-1_47.lib库,并将boost_tread-vc90-mt-gd-1_47.dll放入工程文件夹debug下。

2.5.1互斥量

Boost线程库支持两大类互斥体,包括简单互斥体(simple mutex)和递归互斥体(recursive mutex)。如果同一个线程对互斥体上了两次锁,就会发生死锁(deadlock),也就是说所有的等待解锁的线程将一直等下去。有了递归互斥体,单个 线程就可以对互斥体多次上锁,当然也必须解锁同样次数来保证其他线程可以对这个互斥体上锁。

boost::mutex:独占式互斥量,是最简单最常用的一种互斥量类型

boost::try_mutex:它是mutex的同义词,为了兼容以前的版本而提供

boost::timed_mutex:他也是独占式的互斥量,但提供超时锁定功能

boost::recursive_mutex:递归式互斥量,可以多次锁定,相应的也要多次解锁

boost::recursive_try_mutex:它是recrusive_mutex的同义词,为兼容以前版本提供

boost::recursive_timed_mutex: 递归式互斥量,基本功能与recrusive_mutex相同,但提供超时锁定功能

boost::shared_mutex:读写锁

(1)scopde_lock

测试demo:

boost::mutex io_mutex;

struct count

{

count(int id) : id(id) { }

void operator()()//重载(),当对象使用()时,会执行程序功能

{

for (int i = 0;i < 5; ++i)

{

boost::mutex::scoped_lock lock(io_mutex);

std::cout << id << ": "<< i<< std::endl;

}

}

int id;

};

int main(int argc,char* argv[])

{

boost::thread thrd1(count(1));

boost::thread thrd2(count(2));

thrd1.join();

thrd2.join();

return 0;

}

结果:

可以看到,在thrd1执行时,thrd2在等待。等到thrd1执行完后,开始thrd2

2Bind

测试demo

boost::mutex io_mutex;

void count(int id)

{

for (int i = 0;i < 10; ++i)

{

boost::mutex::scoped_lock lock(io_mutex);

std::cout << id << ": " <<i<< std::endl;

}

}

int main(int argc,char* argv[])

{

boost::thread thrd1(boost::bind(&count,1));

boost::thread thrd2(boost::bind(&count,2));

thrd1.join();

thrd2.join();

return 0;

}

 

3thread_specific_ptr

Boost线程库提供了智能指针boost::thread_specific_ptr来访问本地存储线程。每一个线程第一次使用这个智能指针的实 例时,它的初值是NULL,所以必须要先检查这个它的只是否为空,并且为它赋值。Boost线程库保证本地存储线程中保存的数据会在线程结束后被清除。

测试demo:

using namespace boost;

using namespace std;

mutex io_mu;

thread_specific_ptr<int> ptr;

struct counts1

{

counts1(int id):id(id){}

void operator()()

{

if(ptr.get() == 0)

ptr.reset(new int(0));

for (int i = 0;i<5;i++)

{

(*ptr)++;

mutex::scoped_lock lock_s(io_mu);

cout<<id<<":"<<*ptr<<endl;

}

}

int id;

};

void mutex_test()

{

thread t1(counts1(1));

thread t2(counts1(2));

t1.join();

t2.join();

}

结果:

3  函数与回调

3.1 bind

头文件:#include<boost/bind.hpp>

bind最多有十个参数,第一个可调用的对象,之后可以接最多九个参数,参数量必须与可调用对象的参数相同。点位符为_1 _2等等,位置可以随意放。点位符可以出现,也可以不出现。

成员函数:第一个参数为成员函数地址,第二个参数为对象。

成员变量:第一个参数为成员变量的地址,第二个参数为对象。

注:绑定成员函数时:

1,因为成员函数的指针不能直接调用operator(),因此,它必须被绑定到一个对象或者指针。然后才能得到this指针进而调用成员函数。在bind时,需要用一个占位符的位置,提供一个类的实例、引用或者指针,通过对象作为第一个参数来调用成员函数。

2,必须在成员函数前加取地址符&,表明这是一个函数指针。绑定变量时也一样。

3.2 function

头文件:#include<boost/function.hpp>

测试demo:bind与function合用

using namespace boost;

using namespace std;

struct demo

int print(int a){return a;}

int operator()(int a){return a;}

};

int f(int a)

{return a;}

void function_bind()

{

function<int(int)> fuc;

fuc = f;

cout<<fuc(3)<<endl;

demo dm;

function<int(int)> fuc2;

fuc2 = bind(&demo::print,&dm,_1);//成员函数前必须加去地址符&,dm是提供的类的对象的引用。

cout<<fuc2(34)<<endl;

function<int(demo&,int)> fuc3;//在定义时,形参定义demo类的指针,在绑定时,可用占位符代替

fuc3 = bind(&demo::print,_1,_2);//也可以预留占位符_1,在调用fun3时,将类的对象、实例或引用填入

cout<<fuc3(dm,56)<<endl;

}

结果:

3.3 signals2

头文件:#include<boost/signals2.hpp>

connect() disconnect()连接或断开信号与插槽。

empty() num_slots()返回是否为空,返回插槽数量。

disconnect_all_slots()断开所有信号与插槽的连接。

combiner() set_combiner()用于获取和设置合并器对象

0 0
原创粉丝点击