1引言
base::scoped_ptr是chrome base中的一种智能指针。它的功能涵盖boost的boost::scoped_ptr和c++标准库中的std::auto_ptr,且具备上两者所没有的几种功能:
1)支持数组的管理
如,auto_ptr<std::string[]> std::apAry(new std::string[10]); 这种情况可能会出现潜在的内存泄漏,因为apAry在析构的时候调用的是delete操作符而不是delete[]操作符,因而只会调用数组中第一个对象的析构函数,没有调用剩下的9个对象的析构函数。而base::scoped_ptr<std::string[]> spAry(new std::string[10]);用base::scoped_ptr管理这个数组不会出现内存泄漏。
2)禁用copy和assign,支持 move语义
std::auto_ptr支持了复制构造和赋值操作符,这会带来风险,
因为std::auto_ptr对象在复制或者赋值的时候,其管理的资源对象权责会转移到新的对象上去。由于调用者的失误或者一些其他的原因很容易发生各种错误。
boost::scoped_prt禁止了复制构造和赋值操作符,这又会带来新的问题,即资源的管理权限无法传递到新的对象上去;这就意味着:boost::scoped_ptr指针是不能转换其所有权的。
2类介绍与数组管理
base::scoped_ptr是一种模版类,其声明如下:
template<class T, class D> class scoped_ptr;
T为其管理的对象类型,D为其删除器类型。
base::scoped_ptr的模版参数T跟boost::scoped_ptr和std::auto_ptr的一样,即所管理的资源类型。然而,它比boost::scoped_ptr和std::auto_ptr多一个模版参数,即class D,它是个Functor,用来执行资源对象的删除。base::scoped_ptr之所以用一个D对象来删除资源,是因为它在单个对象时delete,对象数组delete[],malloc对象用free。因而干脆抽象出一个删除器类型,由此也可以看出OO的多态不一定要使用继承,也可以利用C++的模版。
scoped_ptr具有三层结构:封装层、实现层、数据层;
封装层利用模版特化技术,针对单个对象和对象数组实现特化,统一调用实现层。
实现层是封装层模版公共功能的集合,封装层和实现层之间使用了组合而不是继承。
数据层的类继承自Deleter,因此它包含资源对象裸指针的同时又是一个删除器。
类图如上所示。
细分一下scoped_ptr中的类,包括:辅助类、封装类、实现类、数据类。
辅助类:
针对删除器类型,base做一些默认的模版类
template<class T>
struct DefaultDeleter;
//单个对象的删除器
//重载operator(),调用delete
template<class T>
struct DefaultDeleter<T[]>;
//对象数组的删除器,DefaultDeleter的数组特化版
//重载operator(),调用delete[]
struct FreeDeleter;
//malloc出来的对象的删除器,非模版类,因为free的参数是void*
//重载operator(),调用free
封装类:
template<class T,class D = base::DefaultDeleter<T> >
class scoped_ptr;
//单个对象的scoped_ptr
//删除器使用DefaultDeleter<T>
template<class T,class D>
class scoped_ptr<T[], D>;
//数组对象的scoped_ptr
//class scoped_ptr的数组版特化,
//资源类型数组化T[],然而删除器D居然没有特化
//别担心,编译器会自动利用非特化类
//template<class T,class D = base::DefaultDeleter<T> > class scoped_ptr 的删除器
//即base::DefaultDeleter<T>,在这里也就变成了DefaultDeleter<T[]>
实现类:
template<class T,class D >
class scoped_ptr_impl;
//封装类公用模块
数据类:
template<class T,class D >
class scoped_ptr_impl {
struct Date : pulic D {
T* ptr_;
}
}
//删除器对象和资源裸指针
至此base::scope_ptr的骨架已经说明白了。base::scoped_ptr管理对象数组是通过模版特化:包括资源类型的数组特化和删除器的数组特化。
3move语义支持
说完了base::scope_ptr是怎么管理数组的,再来看看它如何禁用copy和assign,支持 move语义(关于move语义,请参考关于move语义请参看:http://blog.csdn.net/pongba/article/details/1684519)。它使用了一种右值手法,具体利用MOVE_ONLY_TYPE_FOR_CPP_03(type, rvalue_type)宏来实现;
#define MOVE_ONLY_TYPE_FOR_CPP_03(type, rvalue_type) \
private: \
struct rvalue_type { \
explicit rvalue_type(type* object) : object(object) {} \
type* object; \
}; \
type(type&); \
void operator=(type&); \
public: \
operator rvalue_type() { return rvalue_type(this); } \
type Pass() { return type(rvalue_type(this)); } \
private:
该宏做了4件事情:
1)把operator = 和 copy构造设置为private,禁止copy和assign
2)定义了rvalue_type类型,该类型包含一个type*数据成员
3)实现了operator rvalue_type;通过rvalue_type的构造函数把type对象转为一个rvalue_type类型对象
4)定义type Pass()函数;把rvalue_type类型对象反转为type对象
同时,如果定义了此宏,也必须要求type类型要定义一个 type::type(rvalue_type rvalue)的构造函数
我们在scoped_ptr中展开此宏,得到如下代码
template <class T, class D = base::DefaultDeleter<T> >
class scoped_ptr {
private:
struct RValue {
explicit RValue(scoped_ptr* object) : object(object) {}
scoped_ptr* object;
};
scoped_ptr(scoped_ptr&);
void operator=(scoped_ptr&);
public:
operator RValue() { return RValue(this); }
scoped_ptr Pass() { return scoped_ptr(RValue(this)); }
// Constructor. Move constructor for C++03 move emulation of this type.
scoped_ptr(RValue rvalue) : impl_(&rvalue.object->impl_) { }
// operator=. Allows assignment from a scoped_ptr rvalue for a convertible
// type and deleter.
//
// IMPLEMENTATION NOTE: C++11 unique_ptr<> keeps this operator= distinct from
// the normal move assignment operator. By C++11 20.7.1.2.3.4, this templated
// form has different requirements on for move-only Deleters. Since this
// implementation does not support move-only Deleters, we do not need a
// separate move assignment operator allowing us to avoid one use of SFINAE.
// You only need to care about this if you modify the implementation of
// scoped_ptr.
template <typename U, typename V>
scoped_ptr& operator=(scoped_ptr<U, V> rhs) {
COMPILE_ASSERT(!base::is_array<U>::value, U_cannot_be_an_array);
impl_.TakeState(&rhs.impl_);
return *this;
}
///...
}
由以上代码可以看出,move集中在Pass()函数上,该函数是由自己得到一个自己的右值对象(函数返回值,临时对象,non-const rvalue)。
接下来我来个小测试:
scoped_ptr<Foo> foo1(new Foo);
scoped_ptr<Foo> foo2 = foo1; //失败
//调用non-const lvalue版的copy构造函数 scoped_ptr(scoped_ptr&);
//该函数为private,编译通不过
scoped_ptr<Foo> foo3; foo3 = foo1; //失败
//调用non-const lvalue版的operator =;
//该函数为private,编译通不过
scoped_ptr<Foo> foo4 = foo1.Pass(); //成功
//foo1.Pass();return non-const rvalue
//找不到scoped_ptr(const scoped_ptr&)
//找到operator RValue() 和 scoped_ptr(RValue rvalue)
//先调用operator RValue()把foo1.Pass()的返回值变为RValue类型
//调用scoped_ptr(RValue rvalue)来构造foo4
scoped_ptr<Foo> f005; foo5 = foo1.Pass(); //成功
//foo1.Pass();return non-const rvalue
//找不到 operator=(const scoped_ptr&)
//找到operator RValue() 和 scoped_ptr(RValue rvalue)
//找到scoped_ptr& operator=(scoped_ptr<U, V> rhs)
//先调用operator RValue()把foo1.Pass()的返回值变为RValue类型
//调用scoped_ptr(RValue rvalue)来构造scoped_ptr& operator=(scoped_ptr<U, V> rhs)的形参
//调用scoped_ptr& operator=(scoped_ptr<U, V> rhs)