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
。
(
2
)
Bind
测试
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;
}
(
3
)
thread_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
。
(
2
)
Bind
测试
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;
}
(
3
)
thread_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()用于获取和设置合并器对象