Chromium基础库使用说明(入门必看)

更新时间:2023-07-13 12:10:30 阅读: 评论:0

Chromium基础库使⽤说明(⼊门必看)
⽬录
Chromium 提供了⼀个类似 WTF 的基础库,甚⾄包含了更多的内容。这个基础库在 Blink 之外被⼴泛使⽤(Blink ⾥⾯仍然使⽤的是WTF),了解它的使⽤对我们实际的代码编写是⼗分重要的。本⽂主要介绍 Chromium 基础库包括的主要内容,并详细说明⼀些重要类型的使⽤⽅式。如果需要了解某个特定⽬录或者⽂件的内容概要,学会的这篇⽂档可以提供⼀个不错的全⾯索引,另外 Chromium 为所有的基础库类型都提供了完整的单元测试,通过阅读单元测试代码了解这些类型的使⽤也是很好的⽅式。
Chromium 基础库概览
Chromium 基础库包括的内容⼗分繁杂,我把其中的主要部分⼤致分为以下⼏类:
容器类型
Chromium 的代码主要使⽤ STL 容器类型,⽐如 std::vector,std::list,另外 GCC 和 MSVC 提供的 STL 扩展容器类型 hash_map 和hash_t 也在 Chromium 中使⽤,不过统⼀放在 ba 名字空间⾥⾯,通过 ba::hash_map,ba_hash_t 使⽤。
教导处是干什么的在 STL 外,Chromium 基础库还提供了⼀些额外的容器类型⽐如 ba::LinkedList,ba::MRUCache 等。
容器类型代码位于 containers ⼦⽬录下。
联系群众智能指针
Chromium 提供了⼀篇官⽅的⽂档  讲解了在 Chromium ⾥⾯常见的⼏种智能指针,最常见的包括
ba::scoped_ptr,ba::ScopedVector,ba::WeakPtr 和 ba::scoped_refptr。
智能指针代码位于 memory ⼦⽬录下。
回调函数
Chromium 基础库提供了 ba::Bind 机制,可以将全局函数和成员函数,跟它的调⽤上下⽂绑定在⼀起,构成⼀个回调函数对象。这个回调函数对象可以被传递,被保存,被当做消息发送到线程的消息循环⾥⾯,最后我们可以通过这个回调函数对象的 Run ⽅法调⽤跟它关联的函数。
回调函数代码位于基础库的根⽬录下。
线程相关
Chromium 基础库提供了⼤量跟线程相关的设施,包括平台线程的封装类型 ba::Thread,线程本地存储 ba::ThreadLocalPointer,消息循环 ba::MessageLoop,线程同步设施 ba::Lock,ba::WaitableEvent 等等,还有原⼦操作和内存屏障的⽀持。
线程相关的代码位于 threading,message_loop,synchronization ⼦⽬录下,原⼦操作和内存屏障位于根⽬录的 atomicops.h。
字串处理
Chromium 使⽤ std::string 作为字串容器,官⽅⽂档  提供了在 Chromium ⾥⾯字串使⽤的⼀些说明。另外 strings ⼦⽬录下提供了⼀些针对字串的辅助操作设施。
⽂件操作
Chromium 基础库的 ba::File 提供了⽂件相关的操作,相关的代码位于根⽬录和 files ⼦⽬录下;
计时器
Chromium 基础库的 ba::Timer 提供了计时器相关的操作,相关的代码位于 timer ⼦⽬录下;
⽇志和调试
Chromium 基础库提供了通⽤的⽇志输出和各种调试辅助等机制,相关的代码位于根⽬录, debug 和 profile ⼦⽬录下;
系统监控
包括系统状态监控,电池状态监控和内存监控,分别位于 system_monitor,power_monitor,和 memory ⼦⽬录下;
Android 相关
基础库的 android ⼦⽬录下是 Android 平台相关的代码,除了包括其它基础类型的 Android 适配代码外,还有⼀些 Android 平台特有的类型,像⼀些⽤于 JNI ⽀持的辅助类型。
除了上⾯列举的部分外,基础库还包括的⼀些设施有进程,内存分配器,国际化⽀持,随机数⽣成,Ba64编码,Sha1编码等等,还有⼀些难以归类的⼯具类型。
容器类型
LinkedList
ba::LinkedList 是 std::list 的⼀个替代品,优点是当你拥有⼀个节点对象时,要删除这个节点只需要 O(1) 的复杂度,并且插⼊节点不需要新增分配内存。能够做到这⼀点是因为 LinkedList 要求节点类型必须以 LinkNode 作为基类,⽽ LinkNode 本⾝已经包含了指向前/后节点的指针。下⾯的代码演⽰了 LinkedList 的常见⽤法:
class MyNodeType : public LinkNode<MyNodeType> {
...
};
LinkedList<MyNodeType> list;
草原狼王LinkNode<MyNodeType>* n1 = ...;
LinkNode<MyNodeType>* n2 = ...;
LinkNode<MyNodeType>* n3 = ...;
list.Append(n1);
list.Append(n3);
n2->InrtBefore(n3);
for (LinkNode<MyNodeType>* node = list.head();
node != d();
node = node->next()) {
MyNodeType* value = node->value();
...
}
MRUCache
MRU 是 most recently ud 的缩写,MRUCache 提供了⼀个类似 Map 的容器类型,主要的区别是可以设定容器的最⼤容纳个数,如果超过则⾃动移除最久不被使⽤的那个对象。
MRUCache 实际上还存在⼏种不同的变种:
1. MRUCache 是最常⽤的,它假设⾃⾝不拥有对象,当移除对象时不执⾏删除操作;
2. OwningMRUCache 假设⾃⼰拥有对象,并要求存储对象是使⽤指针类型,在移除对象时会执⾏删除操作;
3. HashingMRUCache 跟 MRUCache 的区别是,它内部使⽤ ba::hash_map ⽽不是 std::map 存储对象,所以也要求键值对象⽀
持 hash 操作;
智能指针
按照官⽅⽂档的说明,什么时候我们应该使⽤什么类型的智能指针:
拥有对象的时候
使⽤ scoped_ptr 或者 ScopedVector,它们可以使⽤来管理所拥有的⾮引⽤计数的堆分配对象。
不拥有对象的时候
使⽤ raw pointer 或者 WeakPtr。如果其它代码拥有对象,但是你需要知道这个对象是否已经被销毁,
就使⽤ WeakPtr,当所关联的对象被销毁的时候 WeakPtr 会⾃动被置空。你可以通过 ⽅法获得关联对象的指针,如果返回值为空则说明对象已经被销毁。
使⽤引⽤计数对象的时候
使⽤ scoped_refptr,不过 Chromium 不⿎励使⽤引⽤计数对象,特别是在多线程场景下,引⽤计数对象会使对象的拥有权难以确定和对象销毁的顺序和时机难以确定。
scoped_ptr
ba::scoped_ptr 是 Chromium ⾥⾯最常⽤的智能指针,⼀些常见的⽤法:
// We put a pointer into a smart pointer at construction time.
scoped_ptr<ba::Value> value(ba::JSONReader::Read(data));
scoped_ptr<Foo> foo_ptr(new Foo(...));
// ...Or by using ret().
scoped_ptr<Bar> bar_ptr; // Like "Bar* bar_ptr = NULL;".
(new Bar(...)); // Now |bar_ptr| is non-NULL and owns the object.
// We can test the smart pointer directly or u get() to e the raw pointer underneath.
if (!value)
return fal;
Foo* raw_ptr = ();
// We can call through the smart pointer as if it were a pointer.
DictionaryValue* dict = NULL;
if (!value->GetAsDictionary(&dict))
return fal;
当 scoped_ptr 作为函数参数使⽤时,这意味着函数的代码会获得参数对象的所有权,函数的调⽤者如果不是使⽤⼀个临时的 scoped_ptr 的话,它需要使⽤ Pass() ⽅法来放弃⾃⼰的 scoped_ptr 对对象的所有权,例程如下:血塞通胶囊
// Foo() takes ownership of |bar|.
void Foo(scoped_ptr<Bar> bar);
...
scoped_ptr<Bar> bar_ptr(new Bar());
Foo(bar_ptr.Pass()); // Pass() makes |bar_ptr| NULL.
Foo(scoped_ptr<Bar>(new Bar())); // No need to u Pass() on temporaries.
如果函数返回⼀个 scoped_ptr,这意味着函数的调⽤者获得返回对象的所有权,例程如下:
// Foo takes ownership of |bar|, and the caller takes ownership of the returned
// object.
scoped_ptr<Bar> Foo(scoped_ptr<Bar> bar) {
if (cond) {
手画图片return bar.Pass(); // Transfers ownership of |bar| back to
// the caller.
}
return scoped_ptr<Bar>(new Bar())); // No Pass() necessary on temporaries.
// Note that on this codepath, |bar| gets deleted here.
}
最后需要注意的是不应该在函数的参数和返回值中使⽤ scoped_ptr 的指针或者引⽤形式(scoped_ptr<>* scoped_ptr<>&),它会模糊所有权的转移,使最终谁拥有对象的所有权难以理解。
ScopedVector
在 STL 容器⾥⾯存储 scoped_ptr, 类似 std::vector<scoped_ptr<T> > 这样的⽤法可能会有问题,⽐如下⾯的代码:
1. std::vector<scoped_ptr<T> > vec;
2. ...
3.
4. // 对象的所有权会从 vec 转移到 scoped_ptr p,并随着 p 被销毁⽽销毁
5. scoped_ptr<T> p = vec[0];
因为上述代码的危险性,所以 Chromium 不⽀持通过 STL 容器存储 scoped_ptr,它提供了 ba::ScopedVector 来满⾜⼤部分这种需求,ScopedVector 拥有存储在它内部的对象,并在移除对象的时候负责销毁对象,如果 ScopedVector 本⾝被销毁,它会销毁它所存储的所有对象。因为 ScopedVector 内部存储的是 raw pointer,就不存在像 std::vector<scoped_ptr<T> > 这样容易误⽤的危险性。
1. ba::ScopedVector<T> vec;
2. ...
3.
4. // 通过 raw pointer p 使⽤对象,不会有所有权的转移
5. T* p = vec[0];
如果需要在其它 STL 容器⾥⾯使⽤智能指针,希望在容器被销毁或者移除元素时⾃动销毁容器存储的对象,可以考虑使⽤ linked_ptr。
WeakPtr
ba::WeakPtr 是所谓的弱指针,Chromium ⿎励更多使⽤ WeakPtr ⽽不是滥⽤需要引⽤计数的 scoped_refptr,因为 WeakPtr 明确不会拥有对象的所有权,也不会影响对象的销毁顺序。
ba::WeakPtr 需要通过 ba::WeakPtrFactory 创建,⼀般情况下它们使⽤的⽅式是这样的:
小学拟人句1. 需要⽀持 WeakPtr 的类型 Controller 拥有⼀个 WeakPtrFactory 的成员变量,外部获取的 WeakPtr 都是通过这个
WeakPtrFactory 创建的;
2. 当 Controller 对象被销毁时,它的 WeakPtrFactory 成员变量也会同时被销毁,WeakPtrFactory 被销毁的同时会将所有通过它创
建的 WeakPtr 置空;
3. Controller 的 WeakPtrFactory 的成员变量⼀般放在最后⾯,这样它就是第⼀个被销毁的成员变量,似乎没有太⼤意义,不过
Chromium 习惯使⽤这样的⽅式;
在多线程环境下使⽤ WeakPtr 和 WeakPtrFactory 需要注意,它们只⽀持这样的⽅式:
1. WeakPtrFactory 和 WeakPtr 属于创建它们的线程,也只能在创建它们的线程将 WeakPtr 置空,检查⼀个 WeakPtr 是否为空,和
访问 WeakPtr 指向的对象;
2. 属于线程 A 的 WeakPtr 可以传递给 线程 B,线程 B 不能直接使⽤这个 WeakPtr,这不是线程安全的,但是它可以使⽤这个
WeakPtr 往线程 A 发送任务(PostTask),因为任务是在线程 A 执⾏的,所以任务执⾏代码本⾝可以使⽤这个 WeakPtr;
scoped_refptr
⽤于⽀持引⽤计数对象的智能指针,要求对象类型继承⾄ RefCounted 或者 RefCountedThreadSafe,后者是线程安全的。Chromium 因为历史遗留的缘故,当前的代码中使⽤ scoped_refptr 的地⽅还⽐较多,但是⽬前官⽅已经不⿎励 scoped_refptr 的使⽤,认为它会导致对象的所有权,和销毁的顺序和时机难以确定,并认为绝⼤部分情况下 scoped_refptr 都可以使⽤ scoped_ptr 和 WeakPtr 来取代,设计本⾝也不应该过多依赖多个线程共享对象这种⽅式。
下⾯是⼀些简单的使⽤例程:
class MyFoo : public RefCounted<MyFoo> {
...
};
void some_function() {
scoped_refptr<MyFoo> foo = new MyFoo();
foo->Method(param);
// |foo| is relead when this function returns
}
无的放矢什么意思void some_other_function() {
麻油的功效与作用
scoped_refptr<MyFoo> foo = new MyFoo();
...
foo = NULL; // explicitly releas |foo|
...
if (foo)
foo->Method(param);
}
{
scoped_refptr<MyFoo> a = new MyFoo();
scoped_refptr<MyFoo> b;
b.swap(a);
// now, |b| references the MyFoo object, and |a| references NULL.
}
{
scoped_refptr<MyFoo> a = new MyFoo();
scoped_refptr<MyFoo> b;
b = a;
// now, |a| and |b| each own a reference to the same MyFoo object.
}
linked_ptr

本文发布于:2023-07-13 12:10:30,感谢您对本站的认可!

本文链接:https://www.wtabcd.cn/fanwen/fan/89/1079823.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:对象   代码   类型   线程   销毁   函数
相关文章
留言与评论(共有 0 条评论)
   
验证码:
推荐文章
排行榜
Copyright ©2019-2022 Comsenz Inc.Powered by © 专利检索| 网站地图