http://hi.baidu.com/_%E2d_%B7%B3_%DE%B2%C2%D2/blog/item/1d7739d92055bb2610df9b5c.html
boost.scoped_ptr已经被tr2建议作为C++标准库的一部分,它的兄弟shared_ptr已经通过tr1即将成为C++标准库的一部分了。boost.scoped_ptr干着和std::auto_ptr几乎一样的事情,但是它们却又本质上的差别。std::auto_ptr具有权限转移的特点,也就是说当你使用一个auto_ptr来构造另外一个auto_ptr的时候,对资源的控制权即发生了转移,这可以通过auto_ptr的源码来看,因为“源码之下,了无秘密”嘛:
template<class _Other>
auto_ptr<_Ty>& operator=(auto_ptr<_Other>& _Right) _THROW0()
{ // assign compatible _Right (assume pointer)
reset(_Right.release());
return (*this);
}
template<class _Other>
auto_ptr(auto_ptr<_Other>& _Right) _THROW0()
: _Myptr(_Right.release())
{ // construct by assuming pointer from _Right
}
auto_ptr<_Ty>& operator=(auto_ptr<_Ty>& _Right) _THROW0()
{ // assign compatible _Right (assume pointer)
reset(_Right.release());
return (*this);
}
release的定义如下:
_Ty *release() _THROW0()
{ // return wrapped pointer and give up ownership
_Ty *_Tmp = _Myptr;
_Myptr = 0;
return (_Tmp);
}
正是由于这个原因使得std::auto_ptr变得不伦不类,使得它的应用领域变得狭隘了很多。boost.scoped_ptr起着类似的作用,只不过你根本无法用“纯天然”的方法像auto_ptr一样夺走它的资源控制权,因为对于scoped_ptr来说,拷贝构造函数和赋值运算符重载都是私有的,况且还没有实现。
template<class T> class scoped_ptr // noncopyable
{
private:
T * px;
scoped_ptr(scoped_ptr const &);
scoped_ptr & operator=(scoped_ptr const &);
typedef scoped_ptr<T> this_type;
void operator==( scoped_ptr const& ) const;
void operator!=( scoped_ptr const& ) const;
在最新的1.39版本中,甚至判等和不等已经被禁止了。
public:
typedef T element_type;
explicit scoped_ptr( T * p = 0 ): px( p ) // never throws
{
#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS)
boost::sp_scalar_constructor_hook( px );
#endif
}
#ifndef BOOST_NO_AUTO_PTR
explicit scoped_ptr( std::auto_ptr<T> p ): px( p.release() ) // never throws
{
#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS)
boost::sp_scalar_constructor_hook( px );
#endif
}
#endif
~scoped_ptr() // never throws
{
#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS)
boost::sp_scalar_destructor_hook( px );
#endif
boost::checked_delete( px );
}
void reset(T * p = 0) // never throws
{
BOOST_ASSERT( p == 0 || p != px ); // catch self-reset errors
this_type(p).swap(*this);
}
T & operator*() const // never throws
{
BOOST_ASSERT( px != 0 );
return *px;
}
T * operator->() const // never throws
{
BOOST_ASSERT( px != 0 );
return px;
}
T * get() const // never throws
{
return px;
}
// implicit conversion to "bool"
#include <boost/smart_ptr/detail/operator_bool.hpp>
void swap(scoped_ptr & b) // never throws
{
T * tmp = b.px;
b.px = px;
px = tmp;
}
};
template<class T> inline void swap(scoped_ptr<T> & a, scoped_ptr<T> & b) // never throws
{
a.swap(b);
}
这些就是它剩下的内容,可见它就是一个RAII的实践,自动帮我们管理了动态分配的内存这么一个作用。
scoped_ptr的实现其实蛮简单的,唯一值得一提的删除部分的那一句话。
boost::checked_delete( px );
通过查看定义和实现我们可以知道它的实现如下:
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;
}
这样做有什么意义呢?实际上它起着一个静态断言的作用,可以防止delete一个具有非平凡析构函数的类指针。
如果你觉得这句话很拗口的话,可以编译一下下面这个程序:
#include <iostream>
using namespace std;
class CTest;
void deletesometh( CTest * p )
{
delete p;
}
int main()
{
deletesometh( (CTest*)0 );
return 0;
}
看看它的给的警告:
warning C4150: 删除指向不完整“CTest”类型的指针;没有调用析构函数
1> e:\documents\visual studio 2008\projects\boost\main.cpp(5) : 参见“CTest”的声明
MSDN的解释如下:
错误消息删除指向不完整“type”类型的指针;没有调用析构函数
调用
下面的示例生成 C4150:
// C4150.cpp// compile with: /W2class IncClass;void NoDestruct( IncClass* pIncClass ){ delete pIncClass;} // C4150, define class to resolveint main(){}
好了,checked_delete的作用就是把这个警告无运行时成本的转换成错误,以防止潜在的错误。因为对于库开发者来说,你永远都不知道用户最终会用什么来具现化你的模板。
编译下面的代码你会得到一系列的错误信息:
#include <iostream>
#include <boost/checked_delete.hpp>
using namespace std;
class CTest;
void deletesometh( CTest * p )
{
// delete p;
boost::checked_delete( p );
}
int main()
{
deletesometh( (CTest*)0 );
return 0;
}
比如说这样的错误信息:
error C2027: 使用了未定义类型“CTest”
1> e:\documents\visual studio 2008\projects\boost\main.cpp(5) : 参见“CTest”的声明
1> e:\documents\visual studio 2008\projects\boost\main.cpp(10): 参见对正在编译的函数 模板 实例化“void boost::checked_delete<CTest>(T *)”的引用
1> with
1> [
1> T=CTest
1> ]
1>d:\boost\include\boost\checked_delete.hpp(32) : error C2118: 负下标
1>d:\boost\include\boost\checked_delete.hpp(34) : warning C4150: 删除指向不完整“CTest”类型的指针;没有调用析构函数
1> e:\documents\visual studio 2008\projects\boost\main.cpp(5) : 参见“CTest”的声明
在Effective STL中Meyer曾经告诫过我们不要使用std::auto_ptr来作为容器的元素,其原因就是其资源控制权的转移特性,然而对于scoped_ptr则不会有这样的问题,因为你使用scoped_ptr来作为容器的元素实际上意义并不大,而且你都没有办法直接替换移动元素等等,比如下面的代码会导致编译错误:
boost::scoped_ptr< string > sp1( new string("haha") );
boost::scoped_ptr< string > sp2( new string("hehe") );
vector< boost::scoped_ptr< string> > vec;
vec.push_back( sp1 );
如果你非要使用某种智能指针来作为容器元素的话,请选择shared_ptr。
对于scoped_array来说,大多数时候我们都不需要选择它,因为vector是一个更好的选择。scoped_array的好处是不会有多余的开销,其实现和scoped_ptr极其类似,区别在于卸载部分和提供operator []等的支持等等。
在他们的实作中有这样的一段处理指令:
#include <boost/smart_ptr/detail/operator_bool.hpp>
这主要是提供智能指针向bool值隐式转换的跨平台支持。