chromium源码阅读(2)-智能指针scoped_ptr

scoped_ptr,顾名思义,是被设计用来管理作用域内指针的声明周期的。在指针对象离开当前作用域后,scoped_ptr负责清理销毁指针对象,从而避免c++程序员管理内存的负担。

把善后工作交给我
1、scoped_ptr用法

1)scoped_ptr

{
    scoped_ptr<Foo> foo(new Foo("wee"));
}  // foo goes out of scope, releasing the pointer with it.

{
    scoped_ptr<Foo> foo;          // No pointer managed.
    foo.reset(new Foo("wee"));    // Now a pointer is managed.
    foo.reset(new Foo("wee2"));   // Foo("wee") was destroyed.
    foo.reset(new Foo("wee3"));   // Foo("wee2") was destroyed.
    foo->Method();                // Foo::Method() called.
    foo.get()->Method();          // Foo::Method() called.
    SomeFunc(foo.release());      
    // SomeFunc takes ownership, foo no longer manages a pointer.
    foo.reset(new Foo("wee4"));   // foo manages a pointer again.
    foo.reset();  
    // Foo("wee4") destroyed, foo no longer manages a pointer.
}  // foo wasn't managing a pointer, so nothing was destroyed.

2)scoped_ptr

{
   scoped_ptr<Foo[]> foo(new Foo[100]);
   foo.get()->Method();  // Foo::Method on the 0th element.
   foo[10].Method();     // Foo::Method on the 10th element.
}

scoped_ptr是movable but not copyable语意的对象,所以在用scoped_ptr作为函数形参时,传递的函数实参必须调用其pass函数,否则编译器会报错,因为scoped_ptr对象本身不支持拷贝。

void TakesOwnership(scoped_ptr<Foo> arg) {
     // Do something with arg
}
// 函数调用
scoped_ptr<Foo> ptr(new Foo);
TakesOwnership(ptr);//错误,编译失败,不支持拷贝
TakeOwnership(ptr.Pass());

同理,scoped_ptr在作为函数返回值的时候,只能通过临时对象或者调用pass函数的方式返回

scoped_ptr<Foo> CreateFoo() {
// No need for calling Pass() because we are constructing a temporary for the return value.
    return scoped_ptr<Foo>(new Foo("new"));
}

scoped_ptr<Foo> PassThru(scoped_ptr<Foo> arg) 
{
   return arg.Pass();
}

scoped_ptr<Foo> ptr(new Foo("yay")); 
scoped_ptr<Foo> ptr2 = CreateFoo();
scoped_ptr<Foo> ptr3 =  PassThru(ptr2.Pass());
}

指针是C++多态实现的基础,scoped_ptr最大限度的实现了指针的行为。scoped_ptr在初始化时将子类的指针赋值给父类指针对象。

scoped_ptr<Foo> foo(new Foo());
scoped_ptr<FooParent> parent(foo.Pass());

在函数返回值中需要将子类scoped_ptr对象转换为父类scoped_ptr对象,需要调用PassAs<>() 函数

scoped_ptr<Foo> CreateFoo() {
     scoped_ptr<FooChild> result(new FooChild());
     return result.PassAs<Foo>();
  }

注意:PassAs<>()不支持scoped_ptr

template <class T>
struct DefaultDeleter {
  DefaultDeleter() {}
  template <typename U> DefaultDeleter(const DefaultDeleter<U>& other) {
    enum { T_must_be_complete = sizeof(T) };
    enum { U_must_be_complete = sizeof(U) };
    COMPILE_ASSERT((base::is_convertible<U*, T*>::value),
                   U_ptr_must_implicitly_convert_to_T_ptr);
  }
  inline void operator()(T* ptr) const {
    enum { type_must_be_complete = sizeof(T) };
    delete ptr;
  }
};

使用sizeof要求T和U是完全类型,如果是不完全类型,编译会报错,同时enum的命名能够很好的提示具体原因。
2)模板特化技巧
scoped_ptr的数组删除器就是上面的DefaultDeleter的一个偏特化版本:

template <class T>
struct DefaultDeleter<T[]> {
  inline void operator()(T* ptr) const {
    enum { type_must_be_complete = sizeof(T) };
    delete[] ptr;
  }

 private:
  template <typename U> void operator()(U* array) const;
};

注意最后那个private函数,重载了小括号操作符(),这个函数只有声明,没有定义,也就是说不能够对它进行调用。这里是为了防止任何类型不一致的数组指针尝试的转型操作。前段时间,微博上左耳朵耗子跟别人讨论一个话题比较热,他写了篇总结《C++的数组不支持多态》,是的,千万不要对数组指针进行转型之后对其施加delete []操作。因为delete []需要对每个数组成员调用析构函数,T array[i]通过*(array + i*sizeof(T))取得对象,如果sizeof(T)是经过转型的,那么你会在一个很有可能不可以callable的内存地址上进行call操作,等着发疯吧。具体可以阅读《More Effective C++》条款3——绝对不要以多态方式处理数组。

3) 明确拒绝不需要的函数
写一个类,如果情况合适,编译器会自动给你添加一些函数,有:默认构造函数、默认析构函数、默认复制构造函数、赋值操作符,当然如果你自己声明了,编译器就不会添加了。有些地方复制行为是禁止的,就比如这里的scoped_ptr,Chrome声明了一个宏,表示不需要编译器多此一举,采取的方法是把他们声明为private并且不定义:

template <class T, class D>
class scoped_ptr_impl {
 public:
 // ......
 private:
 DISALLOW_COPY_AND_ASSIGN(scoped_ptr_impl);

DISALLOW_COPY_AND_ASSIGN的定义位于src\base\basictypes.h文件之中:

// A macro to disallow the copy constructor and operator= functions
// This should be used in the private: declarations for a class

define DISALLOW_COPY_AND_ASSIGN(TypeName) \

  TypeName(const TypeName&);               \
  void operator=(const TypeName&)

关于这一点,更多请参考《Effective C++》条款06:若不想使用编译器自动生成的函数,就该明确拒绝。

4) 桥接模式的使用

template <class T, class D = base::DefaultDeleter<T> >
class scoped_ptr {
 public:
 // ......
 private:
  // Needed to reach into |impl_| in the constructor.
  template <typename U, typename V> friend class scoped_ptr;
  base::internal::scoped_ptr_impl<element_type, deleter_type> impl_;

  // ......
};

参考地址:
http://www.programlife.net/chrome-source-code-scoped_ptr.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值