Boost 学习笔记
scopted_ptr: 一旦获取用户的管理权,就无法取回.
template<class T>
class scopted_ptr{
private:
T * px;
scopted_ptr (scopted_ptr const &);
scopted_ptr & operator = (scopted_ptr const& ); //禁止复制,保证了scopted_ptr 的所有权.
public:
explicit scopted_ptr(T* p =0);//p必须是new的对象.
~scopted_ptr();
void reset(T*p =0);
T& operator*() const;
T * operator->()const;
T * get() const;//小心使用,这将scopted_ptr脱离,不能对这个指针做deleted操作,否则scopted_ptr析构时会再次删除,程序会崩溃.
operator unspecified-bool-type() const;
void swap(scopted_ptr & b);
};
auto_ptr : 可以转让,同时也失去了管理权。
scopted_array:
template<class T> class scopted_array {
public :
explicit scoped_array(T* p = 0);
~scoped_array();
void reset(T* p =0);
T& operator[] (std::ptrdiff_t i) const;
T* get() const;
operator unspecified-bool-type() const;
void swap(scoped_array& b);
};
shared_ptr;
template<class T> class shared_ptr{
public:
typedef T element_type;
shared_ptr();
shared_ptr(Y * p);//获得指向类型T的指针P的管理权,同时引用计数器置为1.这个要求Y必须能够转换为T类型。
template<class Y> explicit shared_ptr(Y* p);
template<class Y,class D> shared_ptr(Y*p, D d);//行为类似shared_ptr(Y*p),但是使用参数d指定了析构时的定制删除器。而不是简单的delete.
~shared_ptr();
shared_ptr(shared_ptr const& r);//从另外一个shared_ptr 获取指针管理权,同时引用计数加1,结果是两个shared_ptr共享一个指针管理权。
template<class Y>explicit shared_ptr(std::auto_ptr<Y> & r);//从一个auto_ptr获得引用计数的管理权,引用计数置为1,同时auto_ptr自动失去管理权.
shared_ptr & operator = (shared_ptr const & r);
template<class Y>shared_ptr & operator = (shared_ptr<Y> const& r);
template<class Y>shared_ptr & operator = (std::auto_ptr<Y> & r);
void reset();//引用计数减少1,停止对指针的共享。
template<class Y> void reset(Y* p);//带参数的reset,原指针引用计数减少1的同时改为管理另外一个指针。
template<class Y,class D> void reset(Y *p,D d);
T& operator*() const;
T* operator->() const;
T* get() const;
bool unique() const; //
long use_count() const; //
operator unspecified-bool-type() const;
void swap(shared_ptr& b);
};
//////////////////
shared_ptr<int> spi(new int);
assert(spi); //bool 语境中隐式转换为bool值。
shared_ptr<string> sps(new string("smart"));
shared_ptr不能使用诸如static_cast<T*>(p.get())的形式这将提供了类似转型函数static_pointer_cast<T>(),const_pointer_cast<T>()和dynamic_pointer_cast<T>(),
他们与标准转型类似,不过返回的是shared_ptr。
//工厂函数
make_shared<T>() 来消除显示的调用new。
template<class T, class... Args>
shared_ptr<T> make_shared(Args && ... args); //最多可以接受10个参数。
#include <boost/make_shared.hpp>
int main(){
shared_ptr<string> sp = make_shared<string>("make_shared");
shared_ptr<vector<int> >spv = make_shared<vector<int> >(10,2);
}
桥接模式:就是利用纯虚函数在子类中实现。
里式替换原则:任何基类出现的地方,子类一定可以出现。
虚析构函数是为了解决基类的指针指向派生类对象,并用基类的指针删除派生类对象。
shared_ptr 删除器:
fg: socket_t *s = open_socket();
shared_ptr<socket_t>p(s,close_socket);//只要传入删除器即可
也可以在函数前面加上地址操作符& , shared_ptr<socket_t>p(s,&close_socket);
shared_ptr<void> :就像一个泛型指针容器.拥有容纳任意类型的能力。
删除器的高级用法:
由于空指针可以是任何指针类型,因此share_ptr<void>还可以实现退出作用域时调用任意函数。
void any_function(void *p ){
cout<<“some operation”<<endl;
}
int main(){
shared_ptr<void>p((void*)0,any_function);
}
weak_ptr: shared_ptr的助手. 获得资源的观测权,但是没有共享资源,它的构造不会引起引用计数的增加
template<class T> class weak_ptr
{
plublic :
weak_ptr();
template<class Y>weak_ptr(shared_ptr<Y> const& r);
weak_ptr(weak_ptr const& r);
~weak_ptr();
weak_ptr & operator=(weak_ptr const& r);
long use_count() const;
bool expired() const; //等价于 use_count == 0;
shared_ptr<T> lock() const; //expired()返回true,可以从被观测的shared_ptr获得一个可用的对象,从而可以操作资源。
void reset();
void swap(weak_ptr<T> & b);
};
fg:
shared_ptr<int> sp(new int(10));
assert(sp.use_count()==1);
weak_ptr<int>wp(sp);
assert(sp.use_count()==1);
if(!wp.expired()){
shared_ptr<int>sp2=wp.lock();
*sp2 = 100;
assert(wp.use_count() ==2);
}
assert(wp.use_count() == 1);
sp.reset();
assert(wp.expired());
assert(!wp.lock());
获取this的shared_ptr ;
#include <boost/enable_shared_from_this.hpp>
#include <boost/make_shared.hpp>
class self_shared: public enable_shared_from_this<self_shared>{
public:
self_shared(int n):x(n){}
int x;
void print(){cout<<"self_shared"<< x <<endl;}
};
int main(){
shared_ptr<self_shared>sp = make_shared<self_shared>(314);
sp->print();
p->x =1000;
}
//intrusive_ptr 侵入式引用计数指针。
//101
pool : 只分配普通数据类型,不能用于类和对象。
template<typename UserAllocator =...>
class pool {
public:
explicit pool(size_type requested_size);
~pool();
size_type get_requested_size() const;
void *malloc();
void *ordered_malloc();
void *ordered_malloc(size_type n);
bool is_from(void * chunk) const;//测试是否是从这个 内存池分出去的。
void free(void *chunk);
void ordered_free(void* chunk);
void ordered_free(void * chunks,size_type n);
bool release_memory();//让内存池释放已经未分配的内存,但已经分配的内存不受影响。
bool purge_memory();//强制释放所有分配的内存。pool的析构就是调用这个,一般不要手动调用。
}
fg:
#include <boost/pool/pool.h>
using namespace std;
int main(){
pool<> p1(sizeof(int));
int *p = (int *)p1.malloc();
assert(p1.is_from(p));
p1.free(p);
for(int i=0;i<100;++i){
p1.ordered_malloc(10);
}
}
栈:函数内部局部变量
堆:new 分配的
自由储存区:malloc分配的
全局静态存储区:全局变量和静态变量。
常态存储区:常量,不允许修改。
object_pool :用于类实例(对象)的内存池
#include <boost/poool/object_pool.hpp>
using namespace boost;
template<typename ElementType>
class object_pool: protected pool{
public:
object_pool();
~object_pool();
//malloc 和 free 被调用时不调用构造函数和析构函数,也就是说只操作一块原始的内存块。尽量少用。
element_type * malloc();
void free(element_type* p);
bool is_from(element_type *p) const;
element_type * construct(...); //直接在内存池中创建对象。
void destory(element_type* p);
}
#include<boost/pool/object_pool.hpp>
using namespace std;
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>p1;
demo_class *p = p1.malloc();
assert(p1.is_from(p));
assert(p->a!=1 || p->b!=2 || p->c != 3); //p都没有初始化
p = p1.construct(7,8,9);
assert(p->a ==7);
object_pool<string> pls;//连续分配string 对象的内存池。
for(int i=0;i<10;++i){
string *ps = pls.construct("hello object_pool");
cout <<*ps<<endl;
}
}
singleton_pool : 可以分配简单数据类型(POD)的内存指针,但是它是一个单件,并提供线程安全。不会自动释放所占空间。除非手动调用release_memory()或purge_memory();
#include <boost/pool/singleton_pool.hpp>
using namespace boost;
template<typename Tag,usigned RequestedSize> // RequestedSize 指示pool分配的大小。
class singleton_pool{
public: static bool is_from(void * ptr);
static void * malloc();
static void * ordered_malloc();
static void * ordered_malloc(size_type n);
static void free(void * ptr);
static void ordered_free(void * ptr);
static void free(void* ptr);
static void ordered_free(void *ptr,size_type n);
static bool release_memory();
static bool purge_memory();
}
单件模式:单件创建分为两种,一:将一个公共构造函数改为私有的,二是:保留类的公共构造函数,通过一个静态成员来决定是否返回一个实例。
BOOST_AUTO 的功能与auto 相似。
为无效值提供了一个更好的处理方式:
optional: 包装可能产生无效值的对象,实现未初始化的概念。<boost/optional.hpp>
#include <boost/optional.hpp>
using namespace boost;
template<class T>
class optional {
public:
optional();
optional(T const& v);
optional(bool condition , T v);
optional & operator = (T const& rhs);
T* operator->();
T& operator*();
T& get();
T* get_ptr();
T const& get_value_or(T const& default) const;
bool operator!() const;
}
/////////////////////////////////
#include <boost/optional.hpp>
using namespace boost;
optional<double> cacl(int x){
return optional<double>(x!=0,1.0/x);
}
optional<double> sqrt_op(double x){
return optional<double>(x>0,sqrt(x));
}
int main(){
optional<double> d = calc(10);
if(d){
cout<<*d<<endl;
}
if(!d){
cout<<"no result"<<endl;
}
}
////////////////////////////////
工厂函数:make_pair(),make_shared(),make_optional():可以根据参数类型自动推导optional的类型,用来辅助创造optional对象。
optional<T> make_optional(T const& v);
optional<T> make_optional(bool condition, T const& v);
make_optional()无法推导出T引用类型的optional对象,因此需要一个optional<T&>的对象,就不能使用make_optional()函数。
#include<boost/optional.hpp>
using namespace std;
int main(){
BOOST_AUTO(x,make_optional(5)));
assert(*x == 5);
BOOST_AUTO(y,make_optional<double>((*x>10),1.0));
assert(!y);
}
optional<T> 要求类型T 具有拷贝意义,因为内部会保存值的拷贝,但是有时候拷贝的代价会很高。是种浪费,因此有了optional就地创建
in_place_factory.
#include <boost/optional.hpp>
#include <boost/utility/im_place_factory.hpp>
using namespace boost;
int main(){
// 就地创建string对象,不要临时对象string.
optional<string> ops(in_place("test in_place_factory"));
cout<<*ops<<endl;
}
boost 赋值: assign;
int main(){
using namespace boost::assign;//启用assign库的功能。
vector<int> v;
v += 1,2,3,4,5,6*6;
set<string> s;
s += "cpp","java","c#","python";
map<int,string>m;
m+= make_pair(1,"one"),make_pair(2,"two");
}
operator += 仅限于应用STL中定义的标准容器。
operator() 提供了更加通用的解决方案。不能直接使用operate(),应当使用assign库提供的三个辅助函数insert(),push_front(),push_back().返回一个代理
对象list_inserter.
#include <boost/assign.hpp>
int main(){
using namespace boost::assign;
vertor<int> v;
push_back(v)(1)(2)(3);
list<string> l;
push_front(l)("cpp")("java")("c#");
set<double>s;
insert(s)(3.14)(0.618);
map<int,string>m;
insert(m)(1,"one")(2,"two");
}
对于拥有push_back()或push_front()成员函数的容器(vertor,list),可以调用assign::push_back()或者assign::push_front,
而对于set和map,则只能使用assign::insert().
初始化容器元素:
list_of() 函数的用法与之前的insert(),push_back()等函数,也重载了括号,逗号操作符。很智能。
减少重复输入:
template<class U>
generic_list& repeat(std::size_t sz, U u);
template<class Nullary_function>
generic_list& repeat_fun(std::size_t sz,Nullary_function fun);
template<class SinglePassIterator>
generic_list& range(SinglePassIterator first, SinglePassIterator last);
template<class SinglePassRange >
generic_list& range(const SinglePassRange& r);
单件模式:
boost.pool的单件实现。
singleton_default.
template<typename T>
struct singleton_default {
public :
typedef T object_type;
static object_type & instance();
}
fg:
#include <boost/pool/detail/singleton.hpp>
using boost::details::pool::singleton_default;
class point{
public:
point(int a=0,int b=0,int c=0):x(a),y(b),z(c){
cout<<"point ctor"<<endl;
}
~point(){
cout<<"point dtor"<<endl;
}
};
int main(){
cout<<"main start"<<endl;
typedef singleton_default<point> origin;
origin::instance.print();
}
boost.serialzation的单件实现
在序列库serialization中另一个单件实现类:singleton.位于 boost::serialization.
singleton:
template<typename T>
class singleton: public boost::noncopyable{
public:
static const T& get_const_instance();
static T& get_mutable_instance();
}
两种用法:
一:
#include<boost/serialization/singleton.hpp>
using boost::serialization::singleton;
class point{...}
int main(){
cout<<"main start"<<endl;
typedef singleton<point> origin;
origin::get_const_instance().print();
origin::get_mutable_instance().print();
cout<<"main() finished"<<endl;
}
二:通过继承的方式。
#include<boost/serialization/singleton.hpp>
using boost::serialization::singleton;
class point : public singleton<point> {...} //注意这里
int main(){
cout<<"main start"<<endl;
typedef singleton<point> origin;
origin::get_const_instance().print();
origin::get_mutable_instance().print();
cout<<"main() finished"<<endl;
}
tribool:三态的布尔逻辑。
字符串与文本处理:
lexical_cast
并发编程:
mutex: 独占式互斥量
try_mutex
timed_mutex : 也是独占试互斥量,但提供超时锁定功能。
recursive_mutex 递归式互斥量,可以多次锁定。相应的也要多次解锁。
recursive_try_mutex
recursive_timed_mutex 递归是互斥量
shared_mutex: multiple-reader/single-writer型共享互斥量。
loack_guard 他们在构造时锁定互斥量,在析构时自动解锁。
basic_atom:
template <typename T>
class basic_atom: noncopyable{
private:
T n;
typedef mutex mutex_t;
mutex_t mu;
public :
T operator ++ (){
mutex_t::scoped_lock lock(mu);
return ++n;
}
operator T(){
return n;
}
}
typedef basic_atom<int> atom_int;
atom_int x;
cout<<++x;
join() :一直阻塞等待。
timed_join() 阻塞等待线程结束。或者阻塞一定的时间段,然后不管线程是否结束都返回。
detach() 线程执行体分离,但是线程会继续执行。
yield() 指示当前线程放弃时间片,允许其他的线程执行。
bind:可以把库函数所需的参数绑定到一个函数对象中,而function则可以存储bind表达式的结果,
interrupt():中断正在被执行的线程。
bind:
bind(f,1,2) => f(1,2)
bind(f,_1,5)(x) => f(x,5);
如果想传入变量的引用。
int i=5;
bind(f,ref(i),_1);
bind(f,cref(i),1);
bind<int>(f,_1,_1)(x) 有些编译器不支持这个用法。
boost::bind(boost::type<int>(),f,_1,_1)(x)
通过pointers to members使用bind
bind将传入的成员(数据成员和成员函数)指针作为第一个参数,其行为如同使用boost::mem_fn将成员指针转换为一个函数对象,即:
bind(&X::f, args); 等价于bind<R>(mem_fn(&X::f), args),其中R为X::f的返回类型(成员函数)或类型(数据成员)。
bind中的第一个参数不参与计算过程,假设如下程序想要实现对于向量v中的每个函数指针,传入一个参数 5:
typedef void (*pf)(int);
std::vector<pf> v;
std::for_each(v.begin(), v.end(), bind(_1, 5));
上述程序并没有实现我们想要的结果:可以通过使用一个帮助函数对象apply,该对象可以将bind的第一个参数作为一个函数对象,如下:
typedef void (*pf)(int);
std::vector<pf> v;
std::for_each(v.begin(), v.end(), bind(apply<void>(), _1, 5));
thread 库在字命名空间this_thread提供了一组函数和类共同完成线程的中断启用和禁用。
线程组:
thread 提供thread_group用于管理一组线程。就像一个线程池。
条件变量:
thread 库提供的另一种等待的同步机制,可以实现线程的通信,它必须与互斥量配合使用,等待另外一个线程中某个事件的发生,然后线程才能继续执行。
thread: condition_variable 和 condition_variable_any,一般情况下使用condition_varible_any。
缓冲区buffer 使用了两个变量cond_put 和 cond_get() 的处理流程与cond_put类似。
#include <stack>
class buffer{
private:
mutex mu;
condition_variable_any cond_put;
condition_variable_any cond_get;
stack<int> stk;
int un_read,capacity;
bool is_full(){
return un_read == capacity;
}
bool is_empty(){
return un_read == 0;
}
public:
buffer(size_t n):un_read(0),capacity(n){}
void put(int x){
{
mutex::scoped_lock lock(mu);
while(is_full){
{
mutex_t::scoped_lock lock(io_mu);
cout<<"full waiting..."<<endl;
}
cond_put.wait(mu);
}
stk.push(x);
++un_read;
}
cond_get.notify_one();
}
void get(int *x){
{
mutex::scoped_lock lock(mu);
while(is_empty()){
{
mutex::scoped_lock(io_mu);
cout<<"empty waiting"<<endl;
}
cond_get.wait(mu);
}
--un_read;
*x = stk.top();
stk.pop();
}
cond_put.notify_one();
}
};
共享互斥量:
shared_mutex 不同于mutex和recursive_mutex,它允许线程获取多个共享所有权和一个专享所有权,实现读写机制,即多个线程读一个线程写。
读线程时:shared_lock<shared_mutex> 写线程时:unique_lock<shared_mutex>.
future; 在很多情况下线程不仅仅要工作还要执行工作,他还可能返回一些计算结果。
funture 使用packaged_task 和 promise 两个模版类来包装异步调用。unique_future 和 shared_future来获取异步调用结果。
future 还提供wait_for_any() 和 wait_for_all()
仅初始化一次:
使多个线程在操作初始化函数时只能有一个线程成功执行。
once_flag of = BOOST_INIT;
void call_func(){
call_once(of,init_count);
}
barrier: 是thread基于条件变量的另一种同步机制,可以用于多个线程同步。当线程执行到barrier时必须要等待,直到所有的线程都到达这个点时才能继续执行。
智能所:boost::mutex::scoped_lock.
线程本地存储:
有时候函数使用了局部变量或者全局变量,因此不能用于多线程,因为无法保证静态变量在线程环境下重入时是否正确。
thread库使用了thread_specific_ptr实现了可移植的线程本地存储机制。
thread_specific_ptr 智能指针。
定时器:
deadline_timer有两种形式的构造函数,都要求有一个io_service 对象,用于提交IO请求,第二个是定时器的终止时间,可以是posix_time。