chromium base::bind 用法

Chromium 提供了 base::Bind 和模版类型 base::Callback 对函数回调提供了支持,下面是一个简单的使用例程,将一个全局函数绑定到一个 Callback 对象,并通过 Callback.Run 调用这个函数:

int Return5() { return 5; }
base::Callback<int(void)> func_cb = base::Bind(&Return5);
LOG(INFO) << func_cb.Run();  // Prints 5.

如果要绑定一个类的成员函数,我们需要为 Bind 方法提供这个类的一个实例对象,把它跟 Callback 对象绑定,为了保证这个对象在 Callback 对象被执行时仍然存活,或者 Callback 对象能够知道这个对象已经被销毁,我们需要提供一个 scoped_refptr 或者 WeakPtr,通过 base::Unretained(ptr) 用 raw pointer 也可以,不过后果自负… 早期 Chromium 的代码使用 scoped_refptr 比较多,现在 Chromium 更倾向于使用 WeakPtr,当然使用 WeakPtr 时我们要注意这个 Callback 只能在 WeakPtr 所属的线程中被调用,因为它是非线程安全的,下面是一个使用 scoped_refptr 的例子:

class Ref : public base::RefCountedThreadSafe<Ref> {
  public:
    int Foo() { return 3; }
    void PrintBye() { LOG(INFO) << "bye."; }
};
scoped_refptr<Ref> ref = new Ref();
base::Callback<void(void)> ref_cb = base::Bind(&Ref::Foo, ref);
LOG(INFO) << ref_cb.Run();  // Prints out 3.

如果绑定的函数需要参数,我们可以事先绑定所有参数对象到 Callback 里面,也可以事先不绑定参数,甚至可以事先只绑定一部分参数,事先绑定所有参数的 Callback 在 Chromium 里面称为闭包 Closure:

void MyFunc(int i, const std::string& str) {}
base::Callback<void(int, const std::string&)> cb = base::Bind(&MyFunc);
cb.Run(23, "hello, world");

void MyFunc(int i, const std::string& str) {}
base::Callback<void(void)> cb = base::Bind(&MyFunc, 23, "hello world");
cb.Run();

base::Closure cb = base::Bind(&MyClass::MyFunc, this, 23, "hello world");

如果想让 Callback 对象拥有跟它绑定的类对象或者参数对象,也可以使用 base::Owned 或者 base::Passed 方法,分别针对 raw pointer 和 scoped_ptr,如果是 scoped_ptr 类型参数的话,在调用时 Callback 就会将这个参数对象的所有权转移给被回调的函数,最后 Callback 对象被销毁时会自动销毁绑定的类对象和参数对象(如果还拥有这个参数对象的话):

MyClass* myclass = new MyClass;
base::Bind(&MyClass::Foo, base::Owned(myclass));

void TakesOwnership(scoped_ptr<Foo> arg) {}
scoped_ptr<Foo> f(new Foo);
// f becomes null during the following call.
base::Closure cb = base::Bind(&TakesOwnership, base::Passed(&f));

总而言之,在使用 Chromium 的回调函数机制时,一定要非常清楚跟 Callback 对象绑定的类对象和参数对象的所有权和生命周期,避免在 Callback 被调用时,访问到已经被销毁的对象。
 

上一篇:在基类中公有,子类私有继承,main()中不能被访问


下一篇:接口测试工具Apifox 基础篇:配置环境