scoped_ptr的构造函数接受一个类型为T*的指针p,创建出一个scoped_ptr对象并在内部保存指针参数p。p不许是一个new表达式动态分配的结构或者为NULL,在对象生命期结束时,析构函数~scoped_ptr会使用delete操作符自动销毁所保存的指针对象,从而正确的回收资源。
scoped_ptr同时把拷贝构造函数和赋值操作符都声明为私有,禁止对智能指针的赋值操作,保证被它管理的指针不能被转让所有权。
operator==和operator!=两个操作符重载都声明为私有的。但scoped_ptr提供了一个可以在bool语境中自动转换成bool值(如if条件表达式),用来测试一个非空指针。
get()函数返回scoped_ptr内部保存的原始指针,可以用在某些要求必须是原始指针的场景(如底层c接口),但使用时必须小心,这将使原始指针脱离scoped_ptr的控制!不能对这个指针做delete操作,否则析构会对已经删除的指针再进行删除操作,发生未定义行为。
scoped_ptr用法基本上和auto_ptr一样,大多数情况下可以相互替换,也可从auto_ptr中获得指针的管理。
两者都不可作为容器的元素,但原因不同:后者因为它的转移语义,后者不支持拷贝和赋值。
两者的根本区别在于指针的所有权。auto_ptr特意被设计为指针的所有权是可转移的,可以再函数之间传递,同一时刻只能有一个auto_ptr指针。而scoped_ptr将拷贝构造函数和赋值函数都声明了私有,拒绝了指针所有权的转让从而保证了指针的绝对安全。
下面给出两者的实例和两者的源代码:
#include <iostream>
#include <boost/smart_ptr.hpp>
#include <string>
using namespace std;
struct posix_file
{
posix_file(const char *filename)
{
cout<<"open file"<<filename<<endl;
}
~posix_file()
{
cout<<"close file"<<endl;
}
};
int main()
{
using boost::scoped_ptr;
//1
scoped_ptr<string> sps(new string("text") );
cout<<*sps<<endl;
cout<<sps->size()<<endl;
//2
scoped_ptr<int> spi(new int);
if( spi )
{
*spi = 100;
cout<<*spi<<endl;
}
spi.reset();
assert( spi.get() == 0); //没有报错
if( !spi )
{
cout<<"spi is NULL"<<endl;
}
spi.reset( &(int){10} );
cout<<*spi<<endl;
assert( *spi == 10);
scoped_ptr<posix_file> spf(new posix_file("data.txt") );
//auto_ptr和scoped_ptr
auto_ptr<int> ap(new int(10) );
scoped_ptr<int> sp(ap); //从ap上获得指针,但不能调用拷贝构造函数。此时ap调用了release函数就成了空指针,不再指向int(10),可参考scoped_ptr.hpp源代码上面详细讲解了。
assert( ap.get() == 0 ); //断言ap,此时ap一定为空指针 如果没有get会报错
ap.reset(new int(20) ); //让auto_ptr从新拥有新指针
cout<< *ap <<" "<< *sp <<endl;
auto_ptr<int> ap2;
ap2 = ap; //从ap上获得原始指针,发生所有权转移
assert(ap == 0 );
cout << "Hello world!" << endl;
return 0;
}
下面是auto_ptr的源代码:
template<typename _Tp1>
struct auto_ptr_ref
{
_Tp1* _M_ptr;
explicit
auto_ptr_ref(_Tp1* __p): _M_ptr(__p) { }
};
template<typename _Tp>
class auto_ptr
{
private:
_Tp* _M_ptr;
public:
/// The pointed-to type.
typedef _Tp element_type;
explicit
auto_ptr(element_type* __p = 0) throw() : _M_ptr(__p) { }
auto_ptr(auto_ptr& __a) throw() : _M_ptr(__a.release()) { }
template<typename _Tp1>
auto_ptr(auto_ptr<_Tp1>& __a) throw() : _M_ptr(__a.release()) { }
auto_ptr& operator=(auto_ptr& __a) throw()
{
reset(__a.release());
return *this;
}
template<typename _Tp1>
auto_ptr& operator=(auto_ptr<_Tp1>& __a) throw()
{
reset(__a.release());
return *this;
}
~auto_ptr() { delete _M_ptr; }
element_type& operator*() const throw()
{
_GLIBCXX_DEBUG_ASSERT(_M_ptr != 0);
return *_M_ptr;
}
element_type* operator->() const throw()
{
_GLIBCXX_DEBUG_ASSERT(_M_ptr != 0);
return _M_ptr;
}
element_type* get() const throw() { return _M_ptr; }
element_type* release() throw()
{
element_type* __tmp = _M_ptr;
_M_ptr = 0;
return __tmp;
}
void reset(element_type* __p = 0) throw()
{
if (__p != _M_ptr)
{
delete _M_ptr;
_M_ptr = __p;
}
}
auto_ptr(auto_ptr_ref<element_type> __ref) throw()
: _M_ptr(__ref._M_ptr) { }
auto_ptr& operator=(auto_ptr_ref<element_type> __ref) throw()
{
if (__ref._M_ptr != this->get())
{
delete _M_ptr;
_M_ptr = __ref._M_ptr;
}
return *this;
}
template<typename _Tp1>
operator auto_ptr_ref<_Tp1>() throw()
{ return auto_ptr_ref<_Tp1>(this->release()); }
template<typename _Tp1>
operator auto_ptr<_Tp1>() throw()
{ return auto_ptr<_Tp1>(this->release()); }
};
scoped_ptr的源代码
#ifndef BOOST_SMART_PTR_SCOPED_PTR_HPP_INCLUDED
#define BOOST_SMART_PTR_SCOPED_PTR_HPP_INCLUDED
// (C) Copyright Greg Colvin and Beman Dawes 1998, 1999.
// Copyright (c) 2001, 2002 Peter Dimov
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// http://www.boost.org/libs/smart_ptr/scoped_ptr.htm
//
#include <boost/assert.hpp>
#include <boostecked_delete.hpp>
#include <boost/detail/workaround.hpp>
#ifndef BOOST_NO_AUTO_PTR
# include <memory> // for std::auto_ptr
#endif
namespace boost
{
// Debug hooks
#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS)
void sp_scalar_constructor_hook(void * p);
void sp_scalar_destructor_hook(void * p);
#endif
// scoped_ptr mimics a built-in pointer except that it guarantees deletion
// of the object pointed to, either on destruction of the scoped_ptr or via
// an explicit reset(). scoped_ptr is a simple solution for simple needs;
// use shared_ptr or std::auto_ptr if your needs are more complex.
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;
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);
}
// get_pointer(p) is a generic way to say p.get()
template<class T> inline T * get_pointer(scoped_ptr<T> const & p)
{
return p.get();
}
} // namespace boost
#endif // #ifndef BOOST_SMART_PTR_SCOPED_PTR_HPP_INCLUDED