文档章节

Chromium的智能指针/引用计数/Callback/Bind

zhangyujsj
 zhangyujsj
发布于 2015/08/22 18:29
字数 1336
阅读 532
收藏 0

「深度学习福利」大神带你进阶工程师,立即查看>>>

这四个东西对使用者来说不难,看懂代码注释里的例子即可,预计1小时左右看懂全部。要去理解其设计思想的话最需要掌握的是模板类的使用,但一般使用者完全不用关心怎么设计的。

使用者的学习路径:

1.智能删除指针scoped_ptr

用作对普通指针的转储,防止忘记delete或不知道哪里delete。它跟引用计数没有关系。

头文件的注释就是使用示例

http://src.chromium.org/viewvc/chrome/trunk/src/base/memory/scoped_ptr.h

template <class T, class D = base::DefaultDeleter<T> > class scoped_ptr

其中Deleter可以被替换,默认的Deleter区分是要delete普通指针还是指针数组,或者用free函数删除malloc的内存。

2.ScopedVector

http://src.chromium.org/viewvc/chrome/trunk/src/base/memory/scoped_vector.h

在析构时会delete其元素的vector,知道它的行为即可。

3.带引用计数的类

http://src.chromium.org/viewvc/chrome/trunk/src/base/memory/ref_counted.h

为了避免模板类的代码膨胀,引入基类base::subtle::RefCountedBase。基类很简单,就是最基本的引用计数,带AddRef和Release函数。

模 板类template <class T> class RefCounted : public subtle::RefCountedBase相对地就只在Release函数内做特殊处理:delete static_cast<const T*>(this)

另外RefCountedThreadSafeBase和模板类RefCountedThreadSafe是线程安全的版本。

4.引用计数的智能指针scoped_refptr

同在ref_counted.h里定义,对RefCounted的子类做引用。scoped_refptr就是构造时调用RefCounted子类的AddRef函数和析构时Release,并提供了操作符的重载。

5.WeakPtr

弱引用指针,用作传递指针但不想更换owner的情况,即明确知道谁去释放但其它引用者不确定其时机,用弱引用指针可随时知道其是否已delete。

http://src.chromium.org/viewvc/chrome/trunk/src/base/memory/weak_ptr.h

看文件里的注释即可。

6.Callback

对函数的闭包封装,头文件的注释就是使用示例

http://src.chromium.org/viewvc/chrome/trunk/src/base/callback.h

要注意注释里提到的对传入参数的要求。Callback最多提供带7个参数的函数封装,其协作类非常多但都不需要去理解。

(理解设计的提示:非常多的模板类,用作抽象各种各样的函数签名;有很多的辅助类和typedef,最好自己整理成图来看清它们的关系)

7.Bind

对Callback的便捷封装,Bind就是返回Callback对象。

http://src.chromium.org/viewvc/chrome/trunk/src/base/bind.h

看看头文件知道它是个模板函数并为不同参数个数做了重载就行了。

(理解设计的提示:查看http://src.chromium.org/viewvc/chrome/trunk/src/base/bind_internal.h文件的注释)



对scoped_ptr的理解:

没有引用计数的类,使用scoped_ptr<class T, class D>。这个模板类中的D是指Deleter,代表如何删除T。引入Deleter最简单的原因就是对数组需要使用delete[]操作符,实际上有4个默认的Deleter。


3个Deleter都是通过重载括号运算符来执行实际的delete操作,而常量长度的数组指针是不允许使用智能指针的,这里也声明出来,能在编译阶段就排除错误。

除了DefaultDeleter,还有一些特殊的Deleter,如disk cache使用的EntryDeleter(disk_cache.h),字节对齐的内存使用的 AlignedFreeDeleter(aligned_memory.h),他们都有自己的括号运算符重载实现,因为这是scoped_ptr模板类要 求的的方式。

scoped_ptr还有个基类template <class T, class D> class scoped_ptr_impl,它实现了scoped_ptr的核心功能,这样抽离出来是因为有些地方不需要更多的功能。这是模板类,多一个函数就可能 多好多个实现。

scoped_ptr_impl定义了内部类Data来继承Deleter,实际就是增加了ptr来保存传入的裸指针(raw pointer / bare pointer)。

struct Data : public D {
    explicit Data(T* ptr_in) : ptr(ptr_in) {}
    Data(T* ptr_in, const D& other) : D(other), ptr(ptr_in) {}
    T* ptr;
};

Data data_;

scoped_ptr_impl的主要函数:

  explicit scoped_ptr_impl(T* p) : data_(p) { }

  ~scoped_ptr_impl() {
    if (data_.ptr != NULL) {
      // Not using get_deleter() saves one function call in non-optimized
      // builds.
      static_cast<D&>(data_)(data_.ptr);
    }
  }
  void reset(T* p) {
    // This is a self-reset, which is no longer allowed: http://crbug.com/162971
    if (p != NULL && p == data_.ptr)
      abort();
    T* old = data_.ptr;
    data_.ptr = NULL;
    if (old != NULL)
      static_cast<D&>(data_)(old);
    data_.ptr = p;
  }
  T* get() const { return data_.ptr; }
  D& get_deleter() { return data_; }
  const D& get_deleter() const { return data_; }
  void swap(scoped_ptr_impl& p2) {
    using std::swap;
    swap(static_cast<D&>(data_), static_cast<D&>(p2.data_));
    swap(data_.ptr, p2.data_.ptr);
  }
  T* release() {
    T* old_ptr = data_.ptr;
    data_.ptr = NULL;
    return old_ptr;
  }

scoped_ptr是独立的模板类

template <class T, class D = base::DefaultDeleter<T> > class scoped_ptr

template <class T, class D> base::scoped_ptr<T[], D>

它有唯一的成员变量

base::internal::scoped_ptr_impl<element_type, deleter_type> impl_
即是组合scoped_ptr_impl,而不是用继承(也就是桥接模式)。impl有的函数,scoped_ptr都有,并多了重载运算符,以便使用者能直接使用智能指针做其它操作:

typedef T element_type


内存释放的流程:scoped_ptr析构=>impl_析构=>调用deleter=>delete element_type


对引用计数的理解:

有引用计数的智能指针则简单多了:


其中T是本身实现了引用计数的类。


为了避免模板类,引入基类:


基类都是这老一套,用变量保存引用数,没啥说的。

模板类:

template <class T>
class RefCounted : public subtle::RefCountedBase {
 public:
  RefCounted() {}

  void AddRef() const {
    subtle::RefCountedBase::AddRef();
  }

  void Release() const {
    if (subtle::RefCountedBase::Release()) {
      delete static_cast<const T*>(this);
    }
  }

 protected:
  ~RefCounted() {}

 private:
  DISALLOW_COPY_AND_ASSIGN(RefCounted<T>);
};


参考:


zhangyujsj
粉丝 25
博文 358
码字总数 224241
作品 0
广州
私信 提问
加载中
请先登录后再评论。
Netty那点事(三)Channel与Pipeline

Channel是理解和使用Netty的核心。Channel的涉及内容较多,这里我使用由浅入深的介绍方法。在这篇文章中,我们主要介绍Channel部分中Pipeline实现机制。为了避免枯燥,借用一下《盗梦空间》的...

黄亿华
2013/11/24
2W
22
【opencv】图形的绘制

1.矩形图像的绘制: 原函数:void cvRectangle(CvArr* img, CvPoint pt1, CvPoint pt2, CvScalar color, int thickness=1, int line_type=8,int shift=0) img就是需要绘制的图像 pt1 and pt......

其实我是兔子
2014/10/08
1.2K
1
DNS 管理系统--NamedManager

NamedManager 是一个基于 Web 的 DNS 管理系统,可用来添加、调整和删除 DNS 的 zones/records 数据,支持 Bind 作为后端的 DNS 服务,支持 IPv4 和 IPv6。...

匿名
2013/01/23
8.8K
0
代码生成器--Codgen

Codgen是一个基于数据库元数据模型,使用freemarker模板引擎来构建输出的代码生成器。freemarker的数据模型结构通常来说都是一个Map树状结构模型,codgen也不例外,它的数据模型这棵树的根节...

黄天政
2013/01/29
1.4W
2
跨平台 3D 游戏引擎--Castle Game Engine

Castle Game Engine 是一个用 Object Pascal 开发的跨平台 3D 游戏引擎。包含一个灵活的 3D 对象系统与开箱即用的水平,项目,智能生物等等。使用 X3D、VRML、Collada 和其他格式实现渲染和处理...

匿名
2013/02/05
2K
0

没有更多内容

加载失败,请刷新页面

加载更多

C#中const和readonly有什么区别? - What is the difference between const and readonly in C#?

问题: What is the difference between const and readonly in C#? C#中const和readonly什么区别? When would you use one over the other? 您什么时候可以使用另一个? 解决方案: 参考一...

fyin1314
35分钟前
25
0
百度地图SDK新版内测邀请

本文作者:用****9 百度地图开放平台为开发者提供七大基础服务能力,其中地图SDK和导航SDK是开发者广泛使用的重要基础服务,为了满足开发者更多使用需求以及提升开发者集成后的应用效果,本次...

百度开发者中心
前天
19
0
获取JavaScript数组中的所有唯一值(删除重复项) - Get all unique values in a JavaScript array (remove duplicates)

问题: I have an array of numbers that I need to make sure are unique. 我需要确定一个唯一的数字数组。 I found the code snippet below on the internet and it works great until th......

javail
今天
11
0
如何检查字符串是否为空? - How to check if the string is empty?

问题: Does Python have something like an empty string variable where you can do: Python是否有类似空字符串变量的内容可以在其中执行: if myString == string.empty: Regardless, wh......

富含淀粉
今天
19
0
您如何存储未跟踪的文件? - How do you stash an untracked file?

问题: I have changes to a file, plus a new file, and would like to use git stash to put them away while I switch to another task. 我对一个文件进行了更改,再加上一个新文件,并希......

技术盛宴
今天
39
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部