boost库学习笔记
1.Boost C++ 库概述
Boost C++ 库 是一组基于C++标准的现代库。 其源码按 Boost Software License 来发布,允许任何人自由地使用、修改和分发。
这些库是平台独立的,且支持大多数知名和不那么知名的编译器。
Boost 社区负责开发和发布 Boost C++ 库。
社区由一个很大的C++开发人员群组组成,这些开发人员来自于全球,他们通过网站 www.boost.org 以及几个邮件列表相互协调。 社区的使命是开发和收集高质量的库,作为C++标准的补充。
那些被证实有价值且对于C++应用开发非常重要的库,将会有很大机会在某天被纳入C++标准中。
Boost
社区在1998年左右出现,当时刚刚发布了C++标准的第一个版本。 从那时起,社区就不断地扩大,现在已成为C++标准化工作中的一个重要角色。 虽然 Boost
社区与标准化委员会之间没有直接的关系,但有部分开发者同时活跃于两方。 下一个版本的C++标准很大可能在2011年通过,其中将扩展一批库,这些库均起源于
Boost 社区。
要增强C++项目的生产力,除了C++标准以外,Boost C++ 库是一个不错的选择。
由于当前版本的C++标准在2003年修订之后,C++又有了新的发展,所以 Boost C++ 库提供了许多新的特性。 由于有了 Boost C++
库,我们无需等待下一个版本的C++标准,就可以立即享用C++演化中取得的最新进展。
Boost C++
库具有良好的声誉,这基于它们的使用已被证实是非常有价值的。 在面试中询问关于 Boost C++
库的知识是常见的,因为知道这些库的开发人员通常也清楚C++的最新创新,并且能够编写和理解现代的C++代码。
2.Boost常用库介绍
关于Boost库怎样安装,我这里不多讲,网上资料很多。我这里重点介绍一下boost的几个库,以便在我们以后的开发中提高工作效率。Boost库文件采用的.hpp的后缀,而不是分成两个文件,也就是”.h+.cpp”,之所以这样做是有理由的,首先就是与普通的C/C++头文件区分,另外一个原因就是使Boost库不需要预先编译,直接引用程序员的工程即可编译链接,方便了库的使用。最后一个(无奈的)原因就是C++编译器的限制,许多编译器尚不支持C++标准提出的模板的分离编译模式,而Boost使用了大量的模板。Boost中90%的库不需要编译,但像data_time、regex、test、thread等库必须编译成静态库或者动态库。好了,言归正传,下面我们来开始学习boost库吧。
2.1日期和时间处理
timer:包含三个主件,分别是:计时器类timer、progress_timer和进度条指示类progress_display。源码比较简单,我们可以借鉴源码处理时间和进度条。在linux操作系统中timer最大只能计时0.596523h(我们可以改写源码,扩大计时时间),但是可以精确到微秒。我们在计时,进度显示中可能会用到,下面我们给一个progress_display库的使用示例。
#include <boost/progress.hpp> #include <fstream> #include <string> #include <vector> #include <iterator> int main() { std::vector<std::string> v(100); std::ofstream fs("test"); boost::progress_display pd(v.size()); std::vector<std::string>::iterator pos; for(pos=v.begin();pos!=v.end();++pos) { fs<<*pos<<std::endl; ++pd; sleep(1); } } 输出结果: 0% 10 20 30 40 50 60 70 80 90 100% |----|----|----|----|----|----|----|----|----|----| *****
上例中实现了将一个容器的内容拷贝到一个文件中的进度条显示的过程。
DateTime:提供了扩展来处理时区的问题,且支持历法日期和时间的格式化输入与输出。Boost.DateTime
只支持基于格里历的历法日期,这通常不成问题,因为这是最广泛使用的历法。
如果你与其它国家的某人有个会议,时间在2010年1月5日,你可以期望无需与对方确认这个日期是否基于格里历。
格里历是教皇 Gregory XIII
在1582年颁发的。 严格来说,Boost.DateTime 支持由1400年至9999年的历法日期,这意味着它支持1582年以前的日期。
因此,Boost.DateTime 可用于任一历法日期,只要该日期在转换为格里历后是在1400年之后。
如果需要更早的年份,就必须使用其它库来代替。
用于处理历法日期的类和函数位于名字空间 boost::gregorian 中,定义于
boost/date_time/gregorian/gregorian.hpp。 要创建一个日期,请使用 boost::gregorian::date
类。
#include <boost/date_time/gregorian/gregorian.hpp> #include <iostream> int main() { boost::gregorian::date d(2010, 1, 30); std::cout << d.year() << std::endl; std::cout << d.month() << std::endl; std::cout << d.day() << std::endl; std::cout << d.day_of_week() << std::endl; std::cout << d.end_of_month() << std::endl; } 输出结果: 2010 Jan 30 Sat 2010-Jan-31
2.2智能指针
shared_ptr:是一个最像指针的“智能指针”,它实现了引用计数型的智能指针,可以自由的拷贝和赋值,在任意的地方共享它,当没有代码使用它是才删除被包装的动态分配的对象。shared_ptr也可以安全的放在标准容器中,可以像使用指针以用使用shared_ptr。性能和使用指针相差无几,却能有效的防止内存泄露。
#include <boost/shared_ptr.hpp> #include <iostream> #include <vector> class Shared { public: Shared() { std::cout << "ctor() called"<<std::endl; } Shared(const Shared & other) { std::cout << "copy ctor() called"<<std::endl; } ~Shared() { std::cout << "dtor() called"<<std::endl; } Shared & operator = (const Shared & other) { std::cout << "operator = called"<<std::endl; } }; int main() { typedef boost::shared_ptr<Shared> SharedSP; typedef std::vector<SharedSP> VShared; VShared v; v.push_back(SharedSP(new Shared())); v.push_back(SharedSP(new Shared())); }
2.3字符串处理和格式化输出
lexical_cast:lexical_cast库进行“字面量”转换,类似C中的atoi函数,可以进行字符串、整数/浮点数之间的字面转换。
#include <boost/lexical_cast.hpp> void test_lexical_cast() { int i = boost::lexical_cast<int>("123"); cout << i << endl; }
format:用于替代C里面的sprintf,优点是类型安全,不会因为类型和参数不匹配而导致程序崩溃,而且还可以重复使用参数。
#include <boost/format.hpp> void test_format() { cout << boost::format("writing %1%, x=%2% : %3%-th try") % "toto" % 40.23 % 50 <<endl; format f("a=%1%,b=%2%,c=%3%,a=%1%"); f % "string" % 2 % 10.0; cout << f.str() << endl; }
string_algo:它是一个非常全面的字符串算法库,提供了大量的字符串操作函数,如大小写无关比较、修剪、特定模式的字串查找等,可以在不使用正则表达式的情况下处理大多数字符串相关问题。
#include <boost/algorithm/string.hpp> Using namespace boost; int main() { string str(“readme.txt”); if(ends_with(str,”txt”)) { cout<<to_upper_copy(str)+”UPPER”<<endl; assert(ends_with(str,”txt”)); } replace_first(str,”readme”,”followme”); cout<<str<<endl; vector<char> v(str.begin(),str.end()); vector<char> v2=to_upper_copy(erase_first_copy(v,”txt”)); for(int i=0;i<v2.size();++i) { cout<<v2[i]; } }
tokenizer:tokenizer库是一个专门用于分词的字符串处理库,可以用简单易用的方法把一个字符串分解成若干个单词。它与string_algo库的分割算法很类似,但是有更多的变化。
#include <boost/tokenizer.hpp> void test_tokenizer() { string s("This is , a ,test!"); boost::tokenizer<> tok(s); for(tokenizer<>::iterator beg=tok.begin(); beg!=tok.end();++beg) { cout << *beg << " "; } }
Xpressive:是一个先进的、灵活的、功能强大的正则表达式库,提供了对正则表达式的全面支持,而且比原来的正则表达式库boost.regex要好的是不需要编译。
#include <boost/xpressive/xpressive_dynamic.hpp> int main() { cregex reg=cregex::compile(“a.c”); assert(regex_match(“abc”,reg)); assert(regex_match(“a+c”,reg)); assert(!regex_match(“ac”,reg)); assert(!regex_match(“abd”,reg)); }
2.4容器
any:是一种通用的数据类型,可以将类型包装后统一放在容器中,最重要的是它是类型安全的。使用方法: any::type() 返回包装的类型 any_cast可用于any到其他类型的转化
#include <boost/any.hpp> void test_any() { typedef std::vector<boost::any> many; many a; a.push_back(2); a.push_back(string("test")); for(unsigned int i=0;i<a.size();++i) { cout<<a[i].type().name()<<endl; try { int result = any_cast<int>(a[i]); cout<<result<<endl; } catch(boost::bad_any_cast & ex) { cout<<"cast error:"<<ex.what()<<endl; } } }
2.5线程库
boost::thread类代表一个执行线程(a thread of
execution),就像std::fstream类代表一个文件一样。缺省构造函数创建一个代表当前执行线程的一个实例。重载构造函数则有一个函数对象作为参数,该函数对象没有实参(argument),也无返回值。重载的构造函数创建一个新的线程,然后调用函数对象。
由于Boost.Threads采用了函数对象,而不是函数指针,因此函数对象携带线程要用到的数据是完全可以的。这种方法更加灵活,而且类型安全。如果再和相关的函数库结合起来,比如Boost.Bind,这种方式可以让你轻松地将任意多的数据传递给新创建的线程。
#include <boost/thread/thread.hpp> #include <iostream> void hello() { std::cout << "Hello world, I'm a thread!" << std::endl; } int main(int argc, char* argv[]) { boost::thread thrd(&hello); // 译注:hello前面的&符号,可要可不要 thrd.join(); return 0; }
不能让多个线程同时访问共享的资源是至关重要的。mutex在同一时间只能允许一个线程访问共享资源。当一个线程需要访问共享资源时,它必须先“锁住”mutex,如果任何其他线程已经锁住了mutex,那么本操作将会一直被阻塞,直到锁住了mutex的线程解锁,这就保证了共享资源,在同一时间,只有一个线程可以访问。
Boost.Threads支持两大类型的mutex:简单mutex和递归mutex。
一个线程有3种可能方法来锁定mutex:
1.
等待并试图对mutex加锁,直到没有其他线程锁定mutex;
2. 试图对mutex加锁,并立即返回,如果其他线程锁定了mutex;
3.
等待并试图对mutex加锁,直到没有其他线程锁定mutex或者直到规定的时间已过。
Boost.Threads允许你挑选最有效率的mutex。为此,Boost.Threads提供了6中类型的mutex,效率由高到低排列:boost::mutex,boost::try_mutex,boost::timed_mutex,boost::recursive_mutex,boost::recursive_try_mutex和boost::recursive_timed_mutex。
Boost.Threads提供Scoped Lock模式,防止死鎖。要构建一个这种类型的锁,需要传递一个mutex引用,构造函数将锁定mutex,析构函数将解锁mutex
boost::mutex io_mutex; struct count { count(int id) : id(id) { } void operator()() { for (int i = 0; i < 10; ++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; }
下面展示了Boost.Bind库如何不写函数对象
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; }