base::scoped_ptr个人理解

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)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值