boost 的 utility
boost 的 utility 包括几个小工具,其中某些工具已经自立门户了。
base from member
这个工具在 boost/utility/base_from_member.hpp 中,主要解决的问题是
class fdoutbuf : public std::streambuf {
public:
explicit fdoutbuf( int fd );
//...
};
class fdostream : public std::ostream {
protected:
fdoutbuf buf;
public:
explicit fdostream( int fd )
: buf( fd ), std::ostream( &buf ) {}
//...
};
这里 fsostream 的构造函数需要初始化 std::ostream 这个父类,而这个父类依赖于其成员 buf,而成员和父类的初始化顺序在 C++ 标准中规定为先初始化父类。因此解决这个问题的基本思路就是依靠标准中规定父类的初始化按照书写顺序,将成员作为 private 继承的对象进行初始化,而 boost 提供的 base_from_member 就是这种简单的解决方案:
#include <boost/utility/base_from_member.hpp>
class fdoutbuf : public std::streambuf {
public:
explicit fdoutbuf( int fd );
//...
} ;
class fdostream
: private boost::base_from_member<fdoutbuf>, public std::ostream {
// Helper typedef's
typedef boost::base_from_member<fdoutbuf> pbase_type;
typedef std::ostream base_type;
public:
explicit fdostream( int fd ) : pbase_type( fd ), base_type( &member ) {}
//...
};
检查是否含有需要的 delete
在某些情况下,我们需要保证某种类型含有需要的 delete 代码,utility 提供了 boost/checked_delete.hpp 提供了几个简单的东西,如 checked_delete、check_array_delete 函数以及对应的 struct。这个问题主要是由 forward declaration 这种方式引起的(称为 incomplete type)。比如我们想使用 my_class,但是并没有 #include 对应的定义,而只是简单的进行 class my_class ; 这时有潜在的问题,如果我们调用了 delete my_class_pointer ; 而 my_class 的析构函数并不是 trivial 的这会如何?特别是 boost 的 smart pointer 在这种情况下会自动的使用默认的 delete 而最终(在链接时)就没有调用 my_class 自己的析构函数,这会导致错误。
如果你想知道为什么这个 utility 能够实现这一点,可以看看下面的代码:
template<class T> inline void
checked_delete(T * x) {
// intentionally complex - simplification causes regressions
typedef char type_must_be_complete[ sizeof(T)? 1: -1 ];
(void) sizeof(type_must_be_complete);
delete x;
}
注意这里使用了 sizeof(T),如果是 incomplete type,调用 sizeof(T) 就会返回 0,这将导致编译错误。第二行代码大概是保证 typedef 不会被编译器忽视吧。
下一个和上一个
utility 提供了基于 ++ 和 — 的 prior 和 next 方法,它们支持大于 1 的步长,像 std::list 的 iterator 并不是 random access iterator,但是支持 ++–,因此不能直接对其 iterator 使用 iter + 5,但可以 boost::next( iter, 5 )。
不可复制的对象
我们知道杜绝(代码层面的,即如果程序写了复制就会产生编译错误)对象复制只需要将该对象的 copy constructor 和 copy assignment 放在 private 段,utility 提供了一个 boost::noncopyable 类用于继承简化这个过程。
[soucecode language="cpp"]
#include
class my_class : private boost::noncopyable {
// blah
} ;
[/sourcecode]
获得地址
可能我们都知道 & 可以获得对象的地址,可是如果一个对象定义了自己的 operator& 就不是那么回事了。utility 提供的 addressof 可以帮助我们获得地址,而不管有没有这种 operator 的影响。这个很神奇的结果自然会依赖于暴力的 reinterpret_cast 啦。
获得返回类型
参见下面的代码
#include <boost/utility/result_of.hpp>
struct functor {
template<class T>
T operator()(T x)
{
return x;
}
};
typedef boost::result_of<
functor(int)
>::type type;
事实上, result_of 有一套方案获得返回类型,一方面如果支持 C++0x 特性 decltype 就会直接使用这个,否则就会使用 result_type 这种 protocol 进行推断,如果这个没有就直接对 functor 进行推断。
使用二进制
我们可以用 0x 和 0 这种表达十六进制和 8 进制的数值,BOOST_BINARY 宏可以让我们使用二进制。
——————
And the LORD God caused a deep sleep to fall on Adam, and he slept: and he took one of his ribs, and closed up the flesh instead thereof;
[...] 在前面就讨论过这个 idiom,如果父类的初始化依赖于成员则会出现问题,因为 C++ 规定父类初始化完才能初始化成员。解决方案是将成员作为 private 继承的部分,写在父类前面,按照规定在前的父类优先初始化。下面我们看看 boost 提供的 pattern 具体干了些啥。 [...]
C++ 的 idioms(四) « demonstrate 的 blog
2012/02/19 at 8:38 PM
[...] delete 的时候的确调用的是对应的 complete type 的 destructor,早些时候在讨论 boost.utility 的时候见过类似的 [...]
C++ 的 idioms(五) « demonstrate 的 blog
2012/02/22 at 10:14 PM