Boost基础学习

    xiaoxiao2025-03-23  18

    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()用于获取和设置合并器对象

    转载请注明原文地址: https://ju.6miu.com/read-1297313.html
    最新回复(0)