boost库学习

一、boost库的简单介绍
    boost是一个准标准库,相当于STL的延续和扩充,它的设计理念和STL比较接近,都是利用泛型让复用达到最大化。不过对比STL,boost更加实用。  STL集中在算法部分,而boost包含了不少工具类,可以完成比较具体的工作。
    boost主要包含一下几个大类:字符串及文本处理、容器、迭代子(Iterator)、算法、函数对象和高阶编程、泛型编程、模板元编程、预处理元编程、并发编程、数学相关、纠错和测试、数据结构、输入/输出、跨语言支持、内存相关、语法分析、杂项。 有一些库是跨类别包含的,就是既属于这个类别又属于那个类别。
    在文本处理部分,conversion/lexcial_cast类用于“用C++”的方法实现数字类型和字符串之间的转换。 主要是替代C标准库中的 atoi、 itoa之类的函数。当然其中一个最大的好处就是支持泛型了。
    format库提供了对流的“printf-like”功能。printf里使用%d、%s等等的参数做替换的方法在很多情况下还是非常方便的,STL的iostream则缺乏这样的功能。format为stream增加了这个功能,并且功能比原始的printf更强。
    regex,这个不多说了,正则表达式库。如果需要做字符串分析的人就会理解正则表达式有多么有用了。
    spirit,这个是做LL分析的框架,可以根据EBNF规则对文件进行分析。(不要告诉我不知道什么是EBNF)。做编译器的可能会用到。一般人不太用的到。
    tokenizer库。我以前经常在CSDN上看到有人问怎么把一个字符串按逗号分割成字符串数组。也许有些人很羡慕VB的split函数。现在,boost的tokenizer也有相同的功能了,如果我没记错的话,这个tokenizer还支持正则表达式,是不是很爽?
    array: 提供了常量大小的数组的一个包装,喜欢用数组但是苦恼数组定位、确定数组大小等功能的人这下开心了。
    dynamic_bitset,动态分配大小的bitset,我们知道STL里有个bitset,为位运算提供了不少方便。可惜它的大小需要在编译期指定。现在好了,运行期动态分配大小的bitset来了。
    graph。提供了图的容器和相关算法。我还没有在程序中用到过图,需要用的人可以看看。
    multi_array提供了对多维数组的封装,应该还是比较有用的。
    并发编程里只有一个库,thread,提供了一个可移植的线程库,不过在Windows平台上我感觉用处不大。因为它是基于Posix线程的,在Windows里对Posix的支持不是很好。
    接下来的 数学和数值 类里,包含了很多数值处理方面的类库,数学类我也不太熟,不过这里有几个类还是很有用的,比如rational分数类,random随机数类,等等。
    static_assert,提供了编译器的assert功能。
    test库,一个单元测试框架,非常不错。
    concept_check提供了泛型编程时,对泛型量的一点检查,不是很完善,不过比没有好。
    数据类型类any,一个安全的可以包含不同对象的类。把它作为容器的元素类型,那么这个容器就可以包含不同类型的元素。比用void *要安全。
    compressed_pair,跟STL里的pair差不多。不过对空元素做了优化。
    tuple,呵呵,也许是某些人梦寐以求的东西。可以让函数返回多个值。
    跨语言支持:python,呵呵,好东东啊,可以将C++的类和函数映射给python使用。以下为几个CSDN上的关于boost.python的中文资料:http://dev.csdn.net/article/19/19828.shtm,http://dev.csdn.net/article/19/19829.shtm,http://dev.csdn.net/article/19/19830.shtm,http://dev.csdn.net/article/19/19831.shtm
    pool:内存池,呵呵,不用害怕频繁分配释放内存导致内存碎片,也不用自己辛辛苦苦自己实现了。
    smart_ptr:智能指针,这下不用担心内存泄漏的问题了吧。不过,C++里的智能指针都还不是十全十美的,用的时候小心点了,不要做太技巧性的操作了。
    date_time,这个是平台、类库无关的实现,如果程序需要跨平台,可以考虑用这个。
    timer,提供了一个计时器,虽然不是Windows里那种基于消息的计时器,不过据说可以用来测量语句执行时间。
    uitlity里提供了一个noncopyable类,可以实现“无法复制”的类。很多情况下,我们需要避免一个类被复制,比如代表文件句柄的类,文件句柄如果被两个实例共享,操作上会有很多问题,而且语义上也说不过去。一般的避免实例复制的方法是把拷贝构造和operator=私有化,现在只要继承一下这个类就可以了,清晰了很多。
     value_initialized:数值初始化,可以保证声明的对象都被明确的初始化,不过这个真的实用吗?似乎写这个比直接写初始化还累。呵呵,仁者见仁了。
    这里面除了regex、python和test需要编译出库才能用,其他的大部分都可以直接源代码应用,比较方便。其实这些库使用都不难。最主要的原因是有些库的使用需要有相关的背景知识,比如元编程、STL、泛型编程等等。

二、多线程:
1、thread库相关的,c++多线程是一个复杂的事情,windows MFC提供了CWinThread类,WaitForSingleObject等待回收线程;
Linux系统提供了createThread,thread join来回收线程。
boost::thread就比较方便了:
1)、boost::thread(boost::bind(&class::func,this)).detach()。thread()启动一个线程,bind线程绑定的需要执行的任务接一个函数指针,detach,父线程不需要管子线程的回收。
2)、boost::thread thd1(func());参数是一个函数调用thd1.join();父线程来进行回收。
2、线程同步用互斥量boost::mutex,锁用boost::mutex::scoped_lock,来进行时序控制。
比如boost::mutex::scoped_lock lock(m_mutex);互斥量相当于是钥匙,lock相当于是锁,当获取这个钥匙的锁生命周期结束后,则钥匙释放。
mutex可以看成是通配的钥匙。还有一种是AutoLock<ThreadMutexLock> lock (&_operMutex);

三、网络编程:
网络编程分为同步模式和异步模式,同步模式是有一个数据块客户端发送过来,服务端就必须处理完才能处理下一个数据块。
异步模式是客户端发送的数据块放入缓存队列,异步处理不阻塞,同步模式是阻塞式的。
1、同步模式:
服务端:
// 创建服务器对象
boost::asio::io_service ios;#asio编程必须的io_service对象,服务端和客户端创建socket和服务端创建acceptor对象要用
boost::asio::ip::tcp::endpoint ep(boost::asio::ip::tcp::v4(),9800);#tcp协议的服务器所在的ip和网络编程开放的端口,客户端连接的ip和端口
boost::asio::ip::tcp::acceptor acceptor(ios,ep);
// 监听连接
while(1){
     boost::asio::ip::tcp::socket sock(ios);#创建socket连接对象
     acceptor.accept(sock);
     cont<<sock.remote_endpoint().address()<<endl;

     boost::thread(boost::bind(svr_handle,sock)).detach();
}
//交互处理

void svr_handle(boost::asio::ip::tcp::socket sock)
{
      string msg;
      sock.write_some(boost::asio::buffer("hello world"));
      char msg[1024];
      sock.read_some(boost::asio::buffer(msg));
      cout<<"client send msg:"<<msg<<endl;

}
客户端:
// 创建客户端对象
boost::asio::io_service ios;#asio编程必须的io_service对象
boost::asio::ip::tcp::endpoint ep("127.0.0.1",9800);
//监听连接
std::shared_ptr<boost::asio::ip::tcp::socket> p_sock(ios);#创建socket连接对象
p_sock->connect(ep);
string msg;
p_sock->write_some(boost::asio::buffer(msg));
char buf[1024];
p_sock->read_some(boost::asio::buffer(buf));

2、异步模式
服务端:
监听由同步模式的accept()变成了async_accept();
读写由同步模式的write_some()、read_some()变成了async_write_some()、async_read_some()
异步模式关键是void Server::run(){ios.run();//io_service的run方法异步处理队列}。
boost::asio::io_service ios;
boost::asio::ip::tcp::endpoint ep(boost::asio::ip::tcp::v4(),9800);
shared_ptr<boost::asio::ip::tcp::socket> s_ptr(new boost::asio::ip::tcp::socket(ios));
boost::asio::ip::tcp::acceptor acc(ios,ep);
start_accept();
ios.run();
void start_accept()
{acc.async_accept(*s_ptr,boost::bind(handle_accept,s_ptr,1));}
void handle_accept(shared_ptr<boost::asio::ip::tcp::socket> s_ptr,boost::system::error_code ec)
{
    if(err) return ;
    socket_ptr sock(new ip::tcp::socket(service));
    start_accept(sock);
}

当接收到客户端连接的时候,handle_accept被调用。当连接之后socket则就能使用了。

客户端:
连接由同步模式的connect()变成了async_connect();
读写由同步模式的write_some()、read_some()变成了async_write_some()、async_read_some()
异步模式关键是void Client::run(){ios.run();//io_service的run方法异步处理队列}。

boost::asio::io_service ios;
boost::asio::ip::tcp::endpoint ep("127.0.0.1",9800);
//监听连接
std::shared_ptr<boost::asio::ip::tcp::socket> p_sock(ios);#创建socket连接对象
p_sock->async_connect(ep,handle_connect);
ios.run();
void handle_connect(const boost::system::error_code ec)
{//如果ec返回成功了,就知道连接是成功的了}
当handle_connect连接上了,则ios.run()就会循环退出。

四、文件系统:
文件系统相关的方法一般都在boost::filesystem命名空间中。
boost::filesystem::path filepath(path);
filepath.parent_path();//获取父路径
filepath.filename();//包括文件扩展名
boost::filesystem::file_size(filepath);//获取文件大小,单位是字节
boost::filesystem::is_regular_file(path);//判断是否是普通文件
boost::filesystem::is_directory(path);//判断是否是目录
boost::filesystem::is_symlink(path);//判断是否是链接文件

五、两个处理二进制数值工具:vector<bool>和bitset.
C++标准为处理二进制数值提供了两个工具:vector<bool>和bitset.
vector<bool> 是对元素类型为bool的vector特化,它内部并不真正存储bool值而是以bit来压缩保存,使用代理技术来操作bit,造成的后果就是它很像容器,大多数情况下的行为与标准容器一样,但它不是容器,不满足容器的定义。
bitset与vector<bool> 类似,同样存储二进制,但它的的大小固定,而且比vector<bool>支持更多的位运算。
两者的优缺点:vector<bool>可以动态增长,但不能方便地进行位运算;bitset则可以方便地对容纳的二进制位做位运算,但是不能动态的增长。
boost.dynamic_bitset 的出现恰好填补了这两者之间的空白,它类似标准库的bitset,提供丰富的位运算,同时长度又是动态可变的。

类摘要
template <typename Block, typename Allocator>
class dynamic_bitset
{
public:
    explicit dynamic_bitset();/// 构造函数
    dynamic_bitset(const dynamic_bitset& b);
    /// 基本操作
    void  swap(dynamic_bitset& b);
    void  resize(size_type num_bit, bool value = false);
    void  clear();
    void  push_back(bool bit);
    void  apend(Block block);
    ///  操作符重载
    bool operator[](size_type pos)const; 
    dynamic_bitset& operator&=(const dynamic_bitset& b);
    dynamic_bitset& operator|=(const dynamic_bitset& b);
    ...
    /// 
    dynamic_bitset&  set();
    dynamic_bitset&  reset();
    dynamic_bitset&  filp();
    /// 测试
    bool test(size_type n) const;
    bool any() const;
    bool none() const;
    dynamic_bitset operator~()const;
    size_type count() const;
    /// 转型到 ulong
    unsigned long to_ulong() cosnt;
    /// 容量操作
    size_type  size()const;
    size_type  num_blocks() const;
    size_type  max_size() const;
    bool       empty() const;
    /// 集合操作
    bool  is_subset_of(const dynamic_bitset& a)const;
    bool  is_proper_subset_of(const dynamic_bitset& a)const;
    /// 查找元素
    size_type  find_first()const;
    size_type  find_next(size_type pos) const;
};

dynamic_bitset 几乎与std::bitset相同,包括接口和行为,唯一的区别是:dynamic_bitset的大小是在构造函数中又参数决定的,而且运行时时动态可变的。
注意:与vecor<bool>和bitset一样,dynamic_bitset不符合标准容器的定义,不是严格意义样的容器,不提供迭代器的支持。

创建与赋值
dynamic_bitset的第一个模板参数Block指示dynamic_bitset以什么整数类型存储二进制位,必须是一个无符号整数,默认是unsigned long。第二个参数Allocator是类内部使用的内存分配器,默认是std::allocator<Block>。   
 - 不带参数的构造函数创建一个大小为0的dynamic_bitset对象
 - 传入参数制定dynamic_bitset的大小并赋初值,像标准容易一样
 - 从另一个dynamic_bitset拷贝构造
 - 从 01 字符串构造(与std::bitset一样都要求是std::string字符串)

 dynamic_bitset<> db1;        /// 空的dynamic_bitset 对象
    dynamic_bitset<> db2(10);    /// 创建一个大小为10的对象
    dynamic_bitset<> db3(0x16,    
    BOOST_BINARY(10101));       //注意这里,使用了boost宏 BOOST_BINARY 构造一个编译期的二进制数
    dynamic_bitset<> db4(string("0100"));  ///字符串构造
    dynamic_bitset<> db5(db3);

    dynamic_bitset<> db6;
    db6 = db4;
    cout << hex << db5.to_ulong() << endl;
    cout << db4[0] << db4[1] << db4[2] << endl; /// operator[]

容器操作
dynamic_bitset 可以使用resize()成员函数在运行时调整容器的大小,扩展或者收缩都是允许的,并且可以用true/false或者1/0指定扩展后新元素的默认值。
如果是扩展,那么原来有的二进制位保持不变,新增的二进制位被指为指定的值:如果是收缩,那么收缩后容量的二进制位保持不变,多余的二进制位被抛弃,此时设置新元素的默认值是无意义的。

    dynamic_bitset<> db;///空的dynamic_bitset对象
    db.resize(10, true);///扩展为10个二进制,全部为1
    cout << db << endl; /// 1111111111

    db.resize(5);       /// 缩小容量为5个二进制
    cout << db << endl; /// 11111
    {
        dynamic_bitset<> db(5,BOOST_BINARY(01110));

        cout << db << endl;
        assert(db.size() == 5);

        db.clear();    /// 清空 效率比resize效率高
        assert(db.empty()&& db.size()==0);

    }
    /// dynamic_bitset 使用Block来存储二进制位,因此,size()函数不能
    /// 反映dynamic_bitset所占用的内存大小。
    assert(dynamic_bitset<>(64).num_blocks()==1);
    assert(dynamic_bitset<>(65).num_blocks()==2);

    {
        dynamic_bitset<> db(5,BOOST_BINARY(01001));
        db.push_back(true); /// 实际上是项二进制最高位添加
        assert(db.to_ulong() == BOOST_BINARY_UL(101001));

    }

    {
        dynamic_bitset<> db(5,BOOST_BINARY(01001));
        db.append(BOOST_BINARY(101));/// 实际上是项二进制最高位添加
        assert(db.size() == sizeof(unsigned long)*8 + 5);
        cout << db << endl; //0000000000000000000000000000010101001
    }
位运算与比较运算
与vector<bool>相似,dynamic_bitset也运用了代理技术,重载了operator[], operator|等操作符,因此可以像普通数字一样访问其中的二进制位,而且能对二进制或者整个容器做任意位运算,当然吹不能做加减乘除
1
    dynamic_bitset<> db1(4, BOOST_BINARY(1010));

    db1[0] &= 1;  ///按位与运算
    db1[1] ^= 1;  ///按位异或运算
    cout << db1 << endl;/// 1000

    dynamic_bitset<> db2(4, BOOST_BINARY(0101));
    assert(db1 > db2);

    cout << (db1 ^ db2) << endl;///1101
    cout << (db1 | db2) << endl;///1101

访问元素
除了使用operator[]直接访问容器内的元素外,dynamic—bitset还有个成员函数用于测试或者重置二进制位。
1.test()函数检测第n位是否为1
2.如果容器中存在二进制位1,那么any()返回true
3.如果容器中不存在二进制位1,那么none()返回true
4.count()函数统计容器中所有值为1的元素数量
5.set()函数可以置全部或者特定的位置的值为0或者1
6.reset()可以置全部或者特定的位置的值为0
7.flip()可以反转全部或者特定的位置的值
8.find_first()从0位置开始查找,返回第一个值为1的位置
9.find_next(pos)从第pos位置开始差值,返回第一个值为1的位置,如果查找不到,返回npos.

dynamic_bitset<> db(4, BOOST_BINARY(0101));
assert(db.test(0) && !db.test(1));
assert(db.any() && !db.none());
assert(db.count() == 2);  ///值为1 的个数
{
    dynamic_bitset<> db(4, BOOST_BINARY(0101));

    db.flip(); /// 反转
    assert(db.to_ulong() == BOOST_BINARY(1010));

    db.set();
    assert(!db.none());

    db.reset();
    assert(!db.any() );

    db.set(1, 1);
    assert(db.count() == 1);

}

{
    dynamic_bitset<> db(5, BOOST_BINARY(00101));
    auto pos = db.find_first();
    assert(pos == 0);

    pos = db.find_next(pos);
    assert(pos == 2);
}

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值