基于 boost 1.82
timer 计时器 过去老的 boost/timer.hpp 已经废弃了,目前推荐使用的是 boost/timer/timer.hpp, 主要包括下面了2个类
class detail boost::timer::cpu_timer计时器 boost::timer::auto_cpu_timer计时器,基于cpu_timer实现,在析构的时候输出耗时
1 2 3 4 5 6 7 struct cpu_times { nanosecond_type wall; nanosecond_type user; nanosecond_type system; void clear () {wall = user = system = 0LL ; } };
默认的输出格式为下:
“%w s wall, %u s user + %s s system = %t s CPU (%p%)\n”
format meaning %w times.wall %u times.user %s times.system %t times.user + times.system %p The percentage of times.wall represented by times.user + times.system
来个简单的例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 #include <boost/timer/timer.hpp> #include <cmath> #include <iostream> using namespace std;using namespace boost;int main () { timer::cpu_timer t; timer::auto_cpu_timer auto_timer (6 , "%ws real time\n" ) ; for (long i = 0 ; i < 100000000 ; ++i) auto _ = sqrt (i * i); cout << t.format(2 , "%us user + %ss system = %ts(%p%)" ) << endl; t.start (); for (long i = 0 ; i < 100000000 ; ++i) auto _ = sqrt (i * i); cout << t.format(2 , "%us user + %ss system = %ts(%p%)" ) << endl; return 0 ; }
split 头文件为 boost/algorithm/string/split.hpp
1 2 3 4 5 6 7 8 9 10 11 12 13 #include <boost/algorithm/string.hpp> #include <iostream> #include <string> #include <set> int main (int argc, char *argv[]) { std::string str = "123,,345,qwe;adq,345" ; std::set<std::string> st; boost::split (st, str, boost::is_any_of (",; " ), boost::token_compress_on); for_each(st.begin (), st.end (), [](const std::string& x) {std::cout << "[" << x << "]\n" ;}); return 0 ; }
默认为 token_compress_off: 表示遇见多个token时候,不合并成一个token, 这时候,,分割后,会多一个空string,表示2个逗号中间的空string
需要链接的库 : libboost_system (通常自动链接)
circular_buffer 环形缓冲区 Boost.Circular_buffer 提供了固定大小的环形缓冲区,当缓冲区满时自动覆盖最旧的数据。C++23 标准库中没有类似功能。
头文件: boost/circular_buffer.hpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 #include <boost/circular_buffer.hpp> #include <iostream> int main () { boost::circular_buffer<int > cb (5 ) ; for (int i = 0 ; i < 7 ; ++i) { cb.push_back (i); std::cout << "Added " << i << ", size: " << cb.size () << ", capacity: " << cb.capacity () << "\n" ; } std::cout << "Contents: " ; for (const auto & item : cb) { std::cout << item << " " ; } std::cout << "\n" ; std::cout << "Front: " << cb.front () << "\n" ; std::cout << "Back: " << cb.back () << "\n" ; std::cout << "cb[2]: " << cb[2 ] << "\n" ; cb.insert (cb.begin () + 2 , 99 ); std::cout << "After insert: " ; for (const auto & item : cb) { std::cout << item << " " ; } std::cout << "\n" ; cb.pop_front (); std::cout << "After pop_front: " ; for (const auto & item : cb) { std::cout << item << " " ; } std::cout << "\n" ; return 0 ; }
需要链接的库 : header-only
heap 优先队列 Boost.Heap 提供了多种优先队列实现,包括二叉堆、斐波那契堆等。C++23 只有 std::priority_queue,功能有限。
头文件: boost/heap/priority_queue.hpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 #include <boost/heap/priority_queue.hpp> #include <iostream> #include <string> int main () { boost::heap::priority_queue<int > pq; pq.push (5 ); pq.push (3 ); pq.push (8 ); pq.push (1 ); pq.push (4 ); std::cout << "Priority queue size: " << pq.size () << "\n" ; std::cout << "Top element: " << pq.top () << "\n" ; while (!pq.empty ()) { std::cout << "Pop: " << pq.top () << "\n" ; pq.pop (); } auto cmp = [](const std::string& a, const std::string& b) { return a.length () < b.length (); }; boost::heap::priority_queue<std::string, boost::heap::compare<decltype (cmp)>> strPq (cmp); strPq.push ("hello" ); strPq.push ("hi" ); strPq.push ("hey there" ); strPq.push ("a" ); std::cout << "\nString priority queue (by length):\n" ; while (!strPq.empty ()) { std::cout << "Pop: " << strPq.top () << "\n" ; strPq.pop (); } boost::heap::fibonacci_heap<int > fibHeap; fibHeap.push (10 ); fibHeap.push (20 ); fibHeap.push (5 ); std::cout << "\nFibonacci heap top: " << fibHeap.top () << "\n" ; return 0 ; }
需要链接的库 : header-only
string_algo 字符串算法 Boost.String_algo 提供了丰富的字符串处理算法,比 STL 的字符串操作更强大。
头文件: boost/algorithm/string.hpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 #include <boost/algorithm/string.hpp> #include <iostream> #include <string> #include <vector> int main () { std::string text = " Hello, World! " ; std::string upper = boost::to_upper_copy (text); std::string lower = boost::to_lower_copy (text); std::cout << "Upper: " << upper << "\n" ; std::cout << "Lower: " << lower << "\n" ; std::string trimmed = boost::trim_copy (text); std::cout << "Trimmed: " << trimmed << "\n" ; std::string replaced = boost::replace_all_copy (text, "World" , "Boost" ); std::cout << "Replaced: " << replaced << "\n" ; if (boost::contains (text, "Hello" )) { std::cout << "Contains 'Hello'\n" ; } if (boost::starts_with (text, " " )) { std::cout << "Starts with spaces\n" ; } if (boost::ends_with (text, " " )) { std::cout << "Ends with spaces\n" ; } std::string data = "apple,banana,orange" ; std::vector<std::string> fruits; boost::split (fruits, data, boost::is_any_of ("," )); std::cout << "Fruits:\n" ; for (const auto & fruit : fruits) { std::cout << " " << fruit << "\n" ; } std::string joined = boost::join (fruits, ";" ); std::cout << "Joined: " << joined << "\n" ; std::string removed = boost::erase_all_copy (text, " " ); std::cout << "Removed spaces: " << removed << "\n" ; std::string str = "a-b-c-d-e" ; size_t pos = boost::find_nth (str, "-" , 2 ).begin () - str.begin (); std::cout << "3rd '-' at position: " << pos << "\n" ; std::vector<boost::iterator_range<std::string::iterator>> matches; boost::find_all (matches, str, "-" ); std::cout << "Found " << matches.size () << " '-' characters\n" ; return 0 ; }
需要链接的库 : header-only
tokenizer 字符串分词器 Boost.Tokenizer 提供了灵活的字符串分词功能,支持多种分词策略。
头文件: boost/tokenizer.hpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 #include <boost/tokenizer.hpp> #include <iostream> #include <string> int main () { std::string str1 = "Hello,World,Boost,C++" ; boost::char_separator<char > sep ("," ) ; boost::tokenizer<boost::char_separator<char >> tokens1 (str1, sep); std::cout << "Character separator:\n" ; for (const auto & token : tokens1) { std::cout << " " << token << "\n" ; } std::string str2 = "Hello World Boost" ; boost::char_separator<char > space_sep (" " , "" , boost::drop_empty_tokens) ; boost::tokenizer<boost::char_separator<char >> tokens2 (str2, space_sep); std::cout << "\nSpace separator (drop empty):\n" ; for (const auto & token : tokens2) { std::cout << " " << token << "\n" ; } std::string str3 = "1,\"Hello, World\",3.14" ; boost::escaped_list_separator<char > els ("\\" , "," , "\"" ) ; boost::tokenizer<boost::escaped_list_separator<char >> tokens3 (str3, els); std::cout << "\nEscaped list separator (CSV-like):\n" ; for (const auto & token : tokens3) { std::cout << " " << token << "\n" ; } std::string str4 = "1234567890" ; int offsets[] = {3 , 3 , 4 }; boost::offset_separator off_sep (offsets, offsets + 3 ) ; boost::tokenizer<boost::offset_separator> tokens4 (str4, off_sep) ; std::cout << "\nOffset separator (fixed width):\n" ; for (const auto & token : tokens4) { std::cout << " " << token << "\n" ; } return 0 ; }
需要链接的库 : header-only
lockfree 无锁数据结构 Boost.Lockfree 提供了无锁队列、栈等数据结构,用于高并发场景。C++23 标准库中没有类似功能。
头文件: boost/lockfree/queue.hpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 #include <boost/lockfree/queue.hpp> #include <boost/lockfree/stack.hpp> #include <iostream> #include <thread> #include <vector> int main () { boost::lockfree::queue<int > q (100 ) ; auto producer = [&]() { for (int i = 0 ; i < 1000 ; ++i) { while (!q.push (i)) { } } }; std::atomic<int > sum{0 }; auto consumer = [&]() { int value; while (true ) { if (q.pop (value)) { sum += value; } else { if (sum.load () >= 499500 ) { break ; } } } }; std::thread t1 (producer) ; std::thread t2 (consumer) ; t1. join (); t2. join (); std::cout << "Sum: " << sum << "\n" ; boost::lockfree::stack<int > s (100 ) ; for (int i = 0 ; i < 10 ; ++i) { s.push (i); } std::cout << "Stack contents:\n" ; int value; while (s.pop (value)) { std::cout << value << " " ; } std::cout << "\n" ; return 0 ; }
需要链接的库 : header-only
pool 内存池 Boost.Pool 提供了高性能的内存池实现,适用于频繁分配/释放小对象的场景。
与 jemalloc/tcmalloc 的关系 你可能会问:“有了 jemalloc/tcmalloc 这类高性能 malloc,还需要 Boost.Pool 吗?”
答案是:jemalloc 解决的是通用内存分配问题,Pool 解决的是对象池语义问题 。二者不在同一层面:
特性 jemalloc/tcmalloc Boost.Pool 层级 系统级 malloc 替换 应用级对象池 分配粒度 通用内存块 固定大小对象 构造/析构 只分配内存 可以分离构造和分配 批量释放 不支持 支持 purge_memory() 一次性释放整个池 对象重用 无 释放的对象回到池中复用
Pool 相比 jemalloc 的优势场景 :
链表/树节点管理 :需要频繁 new/delete 节点,但生命周期跟随整个数据结构游戏对象池 :子弹、粒子等对象需要快速创建销毁,且经常批量清除内存和构造分离 :只想分配原始内存,稍后或选择性构造对象避免频繁系统调用 :即使 jemalloc 也有 overhead,Pool 完全在用户态简单说:jemalloc 让 new/delete 更快,Pool 让你少用甚至不用 new/delete。
头文件: boost/pool/object_pool.hpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 #include <boost/pool/object_pool.hpp> #include <iostream> #include <vector> class Node {public : int value; Node* next; Node (int v) : value (v), next (nullptr ) {} ~Node () { std::cout << "Node " << value << " destroyed\n" ; } };int main () { boost::object_pool<Node> nodePool; std::cout << "Creating nodes from pool:\n" ; Node* n1 = nodePool.construct (1 ); Node* n2 = nodePool.construct (2 ); Node* n3 = nodePool.construct (3 ); n1->next = n2; n2->next = n3; std::cout << "Nodes linked: " << n1->value << " -> " << n1->next->value << " -> " << n2->next->value << "\n" ; nodePool.destroy (n1); nodePool.destroy (n2); nodePool.destroy (n3); std::cout << "\nCreating more nodes:\n" ; std::vector<Node*> nodes; for (int i = 0 ; i < 1000 ; ++i) { nodes.push_back (nodePool.construct (i)); } std::cout << "Pool memory used: " << nodePool.get_memory_usage () << "\n" ; std::cout << "Pool size: " << nodePool.get_free_count () << "\n" ; nodes.clear (); nodePool.purge_memory (); std::cout << "After purge, free count: " << nodePool.get_free_count () << "\n" ; return 0 ; }
需要链接的库 : header-only
lexical_cast 类型转换 Boost.Lexical_cast 提供了类似 Python 的类型转换功能。
头文件: boost/lexical_cast.hpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 #include <boost/lexical_cast.hpp> #include <iostream> #include <string> #include <vector> int main () { std::string strNum = "123" ; int num = boost::lexical_cast <int >(strNum); std::cout << "String to int: " << num << "\n" ; double d = boost::lexical_cast <double >("3.14159" ); std::cout << "String to double: " << d << "\n" ; int n = 456 ; std::string str = boost::lexical_cast <std::string>(n); std::cout << "Int to string: " << str << "\n" ; bool b = boost::lexical_cast <bool >("true" ); std::cout << "String to bool: " << std::boolalpha << b << "\n" ; std::vector<int > vec = boost::lexical_cast<std::vector<int >>("[1,2,3,4,5]" ); std::cout << "Vector from string: " ; for (int v : vec) { std::cout << v << " " ; } std::cout << "\n" ; struct Point { int x, y; }; try { Point p = boost::lexical_cast <Point>("(10,20)" ); std::cout << "Point: (" << p.x << ", " << p.y << ")\n" ; } catch (const boost::bad_lexical_cast& e) { std::cout << "Conversion failed: " << e.what () << "\n" ; } return 0 ; }
需要链接的库 : header-only
noncopyable 不可复制类 Boost.Noncopyable 提供了一个简洁的方式来禁止类的拷贝构造和赋值操作。C++11 后可以使用 = delete 实现,但 noncopyable 仍然是一个清晰表达意图的方式。
头文件: boost/noncopyable.hpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 #include <boost/noncopyable.hpp> #include <iostream> class Singleton : boost::noncopyable {public : static Singleton& instance () { static Singleton inst; return inst; } void doSomething () { std::cout << "Singleton working\n" ; } private : Singleton () = default ; };class ModernSingleton {public : static ModernSingleton& instance () { static ModernSingleton inst; return inst; } void doSomething () { std::cout << "ModernSingleton working\n" ; } ModernSingleton (const ModernSingleton&) = delete ; ModernSingleton& operator =(const ModernSingleton&) = delete ; private : ModernSingleton () = default ; };int main () { Singleton::instance ().doSomething (); ModernSingleton::instance ().doSomething (); return 0 ; }
何时使用 noncopyable vs = delete :
场景 推荐方式 新代码(C++11+) = delete 更直观需要同时禁止移动 = delete 更灵活代码需要兼容旧标准 boost::noncopyable表达"这个类设计上不可复制"的语义 两者皆可
需要链接的库 : header-only
bimap 双向映射 Boost.Bimap 提供双向映射,可以从 key 查 value,也可以从 value 查 key,两边都是"主键"。std::map/std::unordered_map 只能单向。
头文件: boost/bimap.hpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 #include <boost/bimap.hpp> #include <iostream> #include <string> int main () { boost::bimap<std::string, int > bm; bm.insert ({"alice" , 1001 }); bm.insert ({"bob" , 1002 }); bm.insert ({"carol" , 1003 }); std::cout << "alice -> " << bm.left.at ("alice" ) << "\n" ; std::cout << "1003 -> " << bm.right.at (1003 ) << "\n" ; for (const auto & [name, id] : bm) { std::cout << name << " : " << id << "\n" ; } return 0 ; }
还可以通过 set_of/unordered_set_of/list_of/vector_of 等修饰符控制两侧的索引类型,例如 bimap<set_of<string>, multiset_of<int>>。当两个方向都需要 O(1) 或 O(log n) 查找时,比维护两个 std::map 互相反向更安全(不会出现两边不一致)。
需要链接的库 : header-only
variant2 类型安全的联合体 Boost.Variant2 是 std::variant 的改进实现,接口与 std::variant 几乎一致,但默认构造保证有值(要求第一个备选类型可默认构造)、visit 在异常路径下行为更可预测。如果项目还在用 C++17 或对 std::variant 的默认构造/异常语义不满,可以直接用。
头文件: boost/variant2.hpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 #include <boost/variant2.hpp> #include <iostream> #include <string> namespace v2 = boost::variant2;int main () { using Value = v2::variant<int , double , std::string>; Value v = 42 ; v = 3.14 ; v = "hello" ; v2::visit ([](const auto & x) { std::cout << "value: " << x << "\n" ; }, v); if (auto p = v2::get_if <std::string>(&v)) { std::cout << "string length: " << p->size () << "\n" ; } std::cout << "is string? " << v2::holds_alternative <std::string>(v) << "\n" ; return 0 ; }
需要链接的库 : header-only
pfr 聚合体反射 Boost.PFR 对纯聚合体(无自定义构造、无私有/保护成员、无虚函数的结构体)做编译期反射,无需宏就能遍历字段、按位置访问、比较、流式输出。C++26 才会有标准反射,PFR 是当下最轻量的替代。
头文件: boost/pfr.hpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 #include <boost/pfr.hpp> #include <iostream> #include <string> struct Point { int x; int y; };struct Person { std::string name; int age; double height; };int main () { Point p{3 , 4 }; std::cout << "x=" << boost::pfr::get <0 >(p) << " y=" << boost::pfr::get <1 >(p) << "\n" ; Point p2{3 , 4 }; std::cout << "equal? " << (p == p2) << "\n" ; Person me{"alice" , 30 , 1.68 }; std::cout << me << "\n" ; boost::pfr::for_each_field(me, [](const auto & f) { std::cout << "field: " << f << "\n" ; }); auto [name, age, height] = me; std::cout << name << " " << age << " " << height << "\n" ; return 0 ; }
最适合的场景是 POD/DTO/配置结构体——既能享受聚合体的简洁定义,又免费获得比较、哈希、IO,不用手写一堆样板。注意:只要结构体不再是聚合体(加了构造函数或私有成员),PFR 就失效。
需要链接的库 : header-only
scope RAII 作用域守卫 Boost.Scope 提供 scope_exit/scope_fail/scope_success,把"退出时必做"的清理动作(释放 C 句柄、回滚事务、关闭文件描述符)封装成 RAII 对象,比手写析构类轻得多。C++23 标准库尚无等价物(std::experimental::scope_exit 一直没进标准)。
头文件: boost/scope/scope_exit.hpp 等
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 #include <boost/scope/scope_exit.hpp> #include <boost/scope/scope_fail.hpp> #include <boost/scope/scope_success.hpp> #include <iostream> #include <cstdio> int main () { auto guard = boost::scope::make_scope_exit ([] { std::cout << "cleanup: always\n" ; }); auto rollback = boost::scope::make_scope_fail ([] { std::cout << "rollback on exception\n" ; }); auto commit = boost::scope::make_scope_success ([] { std::cout << "commit on success\n" ; }); std::FILE* f = std::fopen ("/tmp/x" , "w" ); auto close_guard = boost::scope::make_scope_exit ([f] { if (f) std::fclose (f); }); guard.release (); return 0 ; }
比手写 unique_ptr + 自定义删除器更直白地表达意图:scope_fail 就是事务回滚,scope_success 就是提交。也可以用 unique_ptr<T, Deleter> 模拟 scope_exit,但语义不如 scope_* 清晰。
需要链接的库 : header-only
nowide 跨平台宽字符/UTF-8 Boost.Nowide 把 Windows 上坑爹的 wchar_t/char API(fopen、argv、main、std::cout 等)统一封装成 UTF-8 接口,在 POSIX 上直接透传。这样同一段代码在 Windows 和 Linux 下都能正确处理非 ASCII 路径和命令行参数,不必到处写 #ifdef _WIN32。
头文件: boost/nowide/iostream.hpp 等
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 #include <boost/nowide/args.hpp> #include <boost/nowide/iostream.hpp> #include <boost/nowide/fstream.hpp> #include <string> int main (int argc, char ** argv) { boost::nowide::args a (argc, argv) ; for (int i = 0 ; i < argc; ++i) { boost::nowide::cout << "argv[" << i << "] = " << argv[i] << "\n" ; } std::string path = "/tmp/中文.txt" ; boost::nowide::ofstream out (path) ; out << "hello 你好\n" ; return 0 ; }
需要链接的库 : header-only(部分平台实现依赖系统库)
mp11 编译期元编程 Boost.Mp11 是一个极简的元编程库,把类型列表当 mp_list<T...> 操作,提供 mp_size/mp_at/mp_for_each/mp_transform 等一套函数式接口。比手写可变参数模板递归直观得多,编译速度也快。在需要遍历变参包、做类型过滤/转换时非常顺手。
头文件: boost/mp11.hpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 #include <boost/mp11.hpp> #include <iostream> #include <type_traits> namespace mp = boost::mp11;int main () { using Types = mp::mp_list<int , double , char , float , long >; static_assert (mp::mp_size<Types>::value == 5 ); static_assert (std::is_same_v<mp::mp_at_c<Types, 2 >, char >); mp::mp_for_each <Types>([](auto x) { using T = decltype (x); std::cout << "sizeof = " << sizeof (T) << "\n" ; }); using ConstTypes = mp::mp_transform<std::add_const_t , Types>; static_assert (std::is_same_v<mp::mp_at_c<ConstTypes, 0 >, const int >); using Small = mp::mp_copy_if<Types, [](auto T) { return sizeof (typename decltype (T)::type) < 8 ; }>; static_assert (mp::mp_size<Small>::value == 3 ); return 0 ; }
需要链接的库 : header-only
总结 库 功能 需要链接的动态库 timer 计时器 libboost_timer, libboost_chrono algorithm/string 字符串分割、处理 header-only circular_buffer 环形缓冲区 header-only heap 优先队列 header-only lockfree 无锁数据结构 header-only string_algo 字符串算法 header-only tokenizer 字符串分词器 header-only pool 内存池 header-only lexical_cast 类型转换 header-only noncopyable 不可复制类 header-only bimap 双向映射 header-only variant2 类型安全的联合体 header-only pfr 聚合体反射 header-only scope RAII 作用域守卫 header-only nowide 跨平台 UTF-8/宽字符 header-only mp11 编译期元编程 header-only
注意 : header-only 的库直接包含头文件即可使用。但某些情况下可能仍需要链接 libboost_system 等基础库。timer 需要链接 libboost_timer 和 libboost_chrono。