Boost源码剖析--<boost/smart_ptr/scoped_ptr.hpp>
By 马冬亮(凝霜 Loki)
一个人的战争(http://blog.csdn.net/MDL13412)
头文件:设计哲学:
使用scoped_ptr可以让阅读你代码的程序员知道你的意图--仅仅在当前作用域中使用RAII机制,并且放弃转让所有权。
避免std::auto_ptr在转让所有权语义上的陷阱,同时也让程序员知道此资源不可转让。
常用于Handle/Body(pImpl)惯用法,简化资源管理。
不提供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 // // Comment By: 凝霜 // E-mail: [email protected] // Blog: http://blog.csdn.net/mdl13412 #include <boost/assert.hpp> #include <boost/checked_delete.hpp> #include <boost/detail/workaround.hpp> #ifndef BOOST_NO_AUTO_PTR # include <memory> // for std::auto_ptr #endif namespace boost { // Debug hooks // 这里定义的是用于Boost库开发过程中调试和测试时的回调函数。 #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; // 注意:托管的资源只能被一个scoped_ptr所有,否则会导致资源的意外释放。 void operator==( scoped_ptr const& ) const; void operator!=( scoped_ptr const& ) const; public: typedef T element_type; // explicit的作用是防止隐式转换 // 只有单参数的构造函数才需要此关键字 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 // 由std::auto_ptr构造scoped_ptr,并释放掉std::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 // 检测px是否具有完全类型,防止释放错误。 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 &,:-) // 但是C++自身的语义决定了,这个操作需要返回T *然后编译器会自动去处理相关的事情。 T * operator->() const // never throws { BOOST_ASSERT( px != 0 ); return px; } // 这个是提供给一些需要使用裸指针的场合,例如strcpy()等。 T * get() const // never throws { return px; } // 这个其实就是一个operator unspecified_bool_type() const的重载 // 用于if (sp) 或者 if (!sp)一类的boolean操作 // 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; } }; // 将全局的swap特化,防止调用std::swap产生错误的行为。 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实例:
#include <iostream> #include <cstdlib> #include <boost/smart_ptr/scoped_ptr.hpp> using namespace std; struct Dummy { int id_; explicit Dummy(int id) : id_(id) { } ~Dummy() { cout << "~Dummy() id: " << id_ << endl; } void foo() { cout << "foo() id: " << id_ << endl; } }; int main(int argc, char** argv) { { ::boost::scoped_ptr<Dummy> sp_1(new Dummy(1)); ::boost::scoped_ptr<Dummy> sp_2(new Dummy(2)); sp_1->foo(); sp_2->foo(); } cout << "前面托管的资源超出作用域,在这句话前被释放" << endl; return 0; }
foo() id: 1 foo() id: 2 ~Dummy() id: 2 ~Dummy() id: 1 前面托管的资源超出作用域,在这句话前被释放 运行 成功 (总计时间: 251毫秒)
下面给大家一个pImpl的实例,这是C++中最常用的惯用法。
// Dummy.h #ifndef DUMMY_H #define DUMMY_H #include <boost/scoped_ptr.hpp> class Dummy { public: Dummy(); ~Dummy(); private: class ImplClass; // 这里只有声明,没有实现 ::boost::scoped_ptr<ImplClass> impl_; }; #endif /* DUMMY_H */
// Dummy.cpp #include "Dummy.h" #include <iostream> class Dummy::ImplClass { public: ~ImplClass() { std::cout << "~ImplClass()" << std::endl; } }; Dummy::Dummy() : impl_(new ImplClass) { } Dummy::~Dummy() { }
// main.cpp #include <cstdlib> #include "Dummy.h" int main(int argc, char** argv) { { Dummy dummy; } return 0; }
~ImplClass() 运行 成功 (总计时间: 242毫秒)总结:
scoped_ptr提供了RAII机制,是良好的C++编程风格。
scoped_ptr可以在绝大多数情况下取代std::auto_ptr,而余下的情况则可以使用shared_ptr。
不可以用作STL容器,因为其不支持copy语义。
scoped_ptr比shared_ptr有着更强的暗示,暗示其作用域与对象所有权,更好的帮助其他程序员维护既有代码。
scoped_ptr非常适合实现pImpl惯用法。
scoped_ptr不可以托管动态分配的数组,请使用scoped_array。