
Only consume/ignore the first N args. Change-Id: If9041a5ec37b84417c49a86687cdbcf39bd1f254 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4895798 Commit-Queue: Evan Stade <estade@chromium.org> Reviewed-by: Nicolas Dossou-Gbété <dgn@chromium.org> Reviewed-by: danakj <danakj@chromium.org> Cr-Commit-Position: refs/heads/main@{#1204347}
953 lines
34 KiB
Markdown
953 lines
34 KiB
Markdown
# OnceCallback<> and BindOnce(), RepeatingCallback<> and BindRepeating()
|
|
|
|
[TOC]
|
|
|
|
## Introduction
|
|
|
|
The templated `base::{Once, Repeating}Callback<>` classes are generalized
|
|
function objects. Together with the `base::Bind{Once, Repeating}()` functions in
|
|
base/functional/bind.h, they provide a type-safe method for performing partial
|
|
application of functions.
|
|
|
|
Partial application is the process of binding a subset of a function's arguments
|
|
to produce another function that takes fewer arguments. This can be used to pass
|
|
around a unit of delayed execution, much like lexical closures are used in other
|
|
languages. For example, it is used in Chromium code to schedule tasks on
|
|
different MessageLoops.
|
|
|
|
A callback with no unbound input parameters (`base::OnceCallback<void()>`) is
|
|
called a `base::OnceClosure`. The same pattern exists for
|
|
base::RepeatingCallback, as `base::RepeatingClosure`. Note that this is NOT the
|
|
same as what other languages refer to as a closure -- it does not retain a
|
|
reference to its enclosing environment.
|
|
|
|
### OnceCallback<> And RepeatingCallback<>
|
|
|
|
`base::OnceCallback<>` is created by `base::BindOnce()`. This is a callback
|
|
variant that is a move-only type and can be run only once. This moves out bound
|
|
parameters from its internal storage to the bound function by default, so it's
|
|
easier to use with movable types. This should be the preferred callback type:
|
|
since the lifetime of the callback is clear, it's simpler to reason about when
|
|
a callback that is passed between threads is destroyed.
|
|
|
|
`base::RepeatingCallback<>` is created by `base::BindRepeating()`. This is a
|
|
callback variant that is copyable that can be run multiple times. It uses
|
|
internal ref-counting to make copies cheap. However, since ownership is shared,
|
|
it is harder to reason about when the callback and the bound state are
|
|
destroyed, especially when the callback is passed between threads.
|
|
|
|
Prefer `base::OnceCallback<>` where possible, and use `base::RepeatingCallback<>`
|
|
otherwise.
|
|
|
|
`base::RepeatingCallback<>` is convertible to `base::OnceCallback<>` by the
|
|
implicit conversion.
|
|
|
|
### Memory Management And Passing
|
|
|
|
Pass `base::{Once,Repeating}Callback` objects by value if ownership is
|
|
transferred; otherwise, pass it by const-reference.
|
|
|
|
```cpp
|
|
// |Foo| just refers to |cb| but doesn't store it nor consume it.
|
|
bool Foo(const base::OnceCallback<void(int)>& cb) {
|
|
return cb.is_null();
|
|
}
|
|
|
|
// |Bar| takes the ownership of |cb| and stores |cb| into |g_cb|.
|
|
base::RepeatingCallback<void(int)> g_cb;
|
|
void Bar(base::RepeatingCallback<void(int)> cb) {
|
|
g_cb = std::move(cb);
|
|
}
|
|
|
|
// |Baz| takes the ownership of |cb| and consumes |cb| by Run().
|
|
void Baz(base::OnceCallback<void(int)> cb) {
|
|
std::move(cb).Run(42);
|
|
}
|
|
|
|
// |Qux| takes the ownership of |cb| and transfers ownership to PostTask(),
|
|
// which also takes the ownership of |cb|.
|
|
void Qux(base::RepeatingCallback<void(int)> cb) {
|
|
PostTask(FROM_HERE, base::BindOnce(cb, 42));
|
|
PostTask(FROM_HERE, base::BindOnce(std::move(cb), 43));
|
|
}
|
|
```
|
|
|
|
When you pass a `base::{Once,Repeating}Callback` object to a function parameter,
|
|
use `std::move()` if you don't need to keep a reference to it, otherwise, pass the
|
|
object directly. You may see a compile error when the function requires the
|
|
exclusive ownership, and you didn't pass the callback by move. Note that the
|
|
moved-from `base::{Once,Repeating}Callback` becomes null, as if its `Reset()`
|
|
method had been called. Afterward, its `is_null()` method will return true and
|
|
its `operator bool()` will return false.
|
|
|
|
### Chaining callbacks
|
|
|
|
When you have 2 callbacks that you wish to run in sequence, they can be joined
|
|
together into a single callback through the use of `Then()`.
|
|
|
|
Calling `Then()` on a `base::OnceCallback` joins a second callback that will be
|
|
run together with, but after, the first callback. The return value from the
|
|
first callback is passed along to the second, and the return value from the
|
|
second callback is returned at the end. More concretely, calling `a.Then(b)`
|
|
produces a new `base::OnceCallback` that will run `b(a());`, returning the
|
|
result from `b`.
|
|
|
|
This example uses `Then()` to join 2 `base::OnceCallback`s together:
|
|
```cpp
|
|
int Floor(float f) { return std::floor(f); }
|
|
std::string IntToString(int i) { return base::NumberToString(i); }
|
|
|
|
base::OnceCallback<int(float)> first = base::BindOnce(&Floor);
|
|
base::OnceCallback<std::string(int)> second = base::BindOnce(&IntToString);
|
|
|
|
// This will run |first|, run and pass the result to |second|, then return
|
|
// the result from |second|.
|
|
std::string r = std::move(first).Then(std::move(second)).Run(3.5f);
|
|
// |r| will be "3". |first| and |second| are now both null, as they were
|
|
// consumed to perform the join operation.
|
|
```
|
|
|
|
Similarly, `Then()` also works with `base::RepeatingCallback`; however, the
|
|
joined callback must also be a `base::RepeatingCallback` to ensure the resulting
|
|
callback can be invoked multiple times.
|
|
|
|
This example uses `Then()` to join 2 `base::RepeatingCallback`s together:
|
|
```cpp
|
|
int Floor(float f) { return std::floor(f); }
|
|
std::string IntToString(int i) { return base::NumberToString(i); }
|
|
|
|
base::RepeatingCallback<int(float)> first = base::BindRepeating(&Floor);
|
|
base::RepeatingCallback<std::string(int)> second = base::BindRepeating(&IntToString);
|
|
|
|
// This creates a RepeatingCallback that will run |first|, run and pass the
|
|
// result to |second|, then return the result from |second|.
|
|
base::RepeatingCallback<std::string(float)> joined =
|
|
std::move(first).Then(std::move(second));
|
|
// |first| and |second| are now both null, as they were consumed to perform
|
|
// the join operation.
|
|
|
|
// This runs the functor that was originally bound to |first|, then |second|.
|
|
std::string r = joined.Run(3.5);
|
|
// |r| will be "3".
|
|
|
|
// It's valid to call it multiple times since all callbacks involved are
|
|
// base::RepeatingCallbacks.
|
|
r = joined.Run(2.5);
|
|
// |r| is set to "2".
|
|
```
|
|
|
|
In the above example, casting the `base::RepeatingCallback` to an r-value with
|
|
`std::move()` causes `Then()` to destroy the original callback, in the same way
|
|
that occurs for joining `base::OnceCallback`s. However since a
|
|
`base::RepeatingCallback` can be run multiple times, it can be joined
|
|
non-destructively as well.
|
|
```cpp
|
|
int Floor(float f) { return std::floor(f); }
|
|
std::string IntToString(int i) { return base::NumberToString(i); }
|
|
|
|
base::RepeatingCallback<int(float)> first = base::BindRepeating(&Floor);
|
|
base::RepeatingCallback<std::string(int)> second = base::BindRepeating(&IntToString);
|
|
|
|
// This creates a RepeatingCallback that will run |first|, run and pass the
|
|
// result to |second|, then return the result from |second|.
|
|
std::string r = first.Then(second).Run(3.5f);
|
|
// |r| will be 3, and |first| and |second| are still valid to use.
|
|
|
|
// Runs Floor().
|
|
int i = first.Run(5.5);
|
|
// Runs IntToString().
|
|
std::string s = second.Run(9);
|
|
```
|
|
|
|
If the second callback does not want to receive a value from the first callback,
|
|
you may use `base::IgnoreResult` to drop the return value in between running the
|
|
two.
|
|
|
|
```cpp
|
|
// Returns an integer.
|
|
base::RepeatingCallback<int()> first = base::BindRepeating([](){ return 5; });
|
|
// Does not want to receive an integer.
|
|
base::RepeatingClosure second = base::BindRepeating([](){});
|
|
|
|
// This will not compile, because |second| can not receive the return value from
|
|
// |first|.
|
|
// first.Then(second).Run();
|
|
|
|
// We can drop the result from |first| before running second.
|
|
base::BindRepeating(base::IgnoreResult(first)).Then(second).Run();
|
|
// This will effectively create a callback that when Run() will call
|
|
// `first(); second();` instead of `second(first());`.
|
|
```
|
|
|
|
Note that the return value from |first| will be lost in the above example, and
|
|
would be destroyed before |second| is run. If you want the return value from
|
|
|first| to be preserved and ultimately returned after running both |first| and
|
|
|second|, then you would need a primitive such as the `base::PassThrough<T>()`
|
|
helper in the [base::PassThrough CL](https://chromium-review.googlesource.com/c/chromium/src/+/2493243).
|
|
If this would be helpful for you, please let danakj@chromium.org know or ping
|
|
the CL.
|
|
|
|
### Chaining callbacks across different task runners
|
|
|
|
```cpp
|
|
// The task runner for a different thread.
|
|
scoped_refptr<base::SequencedTaskRunner> other_task_runner = ...;
|
|
|
|
// A function to compute some interesting result, except it can only be run
|
|
// safely from `other_task_runner` and not the current thread.
|
|
int ComputeResult();
|
|
|
|
base::OnceCallback<int()> compute_result_cb = base::BindOnce(&ComputeResult);
|
|
|
|
// Task runner for the current thread.
|
|
scoped_refptr<base::SequencedTaskRunner> current_task_runner =
|
|
base::SequencedTaskRunner::GetCurrentDefault();
|
|
|
|
// A function to accept the result, except it can only be run safely from the
|
|
// current thread.
|
|
void ProvideResult(int result);
|
|
|
|
base::OnceCallback<void(int)> provide_result_cb =
|
|
base::BindOnce(&ProvideResult);
|
|
```
|
|
|
|
Using `Then()` to join `compute_result_cb` and `provide_result_cb` directly
|
|
would be inappropriate. `ComputeResult()` and `ProvideResult()` would run on the
|
|
same thread which isn't safe. However, `base::BindPostTask()` can be used to
|
|
ensure `provide_result_cb` will run on `current_task_runner`.
|
|
|
|
```cpp
|
|
// The following two statements post a task to `other_task_runner` to run
|
|
// `task`. This will invoke ComputeResult() on a different thread to get the
|
|
// result value then post a task back to `current_task_runner` to invoke
|
|
// ProvideResult() with the result.
|
|
OnceClosure task =
|
|
std::move(compute_result_cb)
|
|
.Then(base::BindPostTask(current_task_runner,
|
|
std::move(provide_result_cb)));
|
|
other_task_runner->PostTask(FROM_HERE, std::move(task));
|
|
```
|
|
|
|
### Splitting a OnceCallback in two
|
|
|
|
If a callback is only run once, but two references need to be held to the
|
|
callback, using a `base::OnceCallback` can be clearer than a
|
|
`base::RepeatingCallback`, from an intent and semantics point of view.
|
|
`base::SplitOnceCallback()` takes a `base::OnceCallback` and returns a pair of
|
|
callbacks with the same signature. When either of the returned callback is run,
|
|
the original callback is invoked. Running the leftover callback will result in a
|
|
crash.
|
|
This can be useful when passing a `base::OnceCallback` to a function that may or
|
|
may not take ownership of the callback. E.g, when an object creation could fail:
|
|
|
|
```cpp
|
|
std::unique_ptr<FooTask> CreateFooTask(base::OnceClosure task) {
|
|
std::pair<base::OnceClosure,base::OnceClosure> split
|
|
= base::SplitOnceCallback(std::move(task));
|
|
|
|
std::unique_ptr<FooTask> foo = TryCreateFooTask(std::move(split.first));
|
|
if (foo)
|
|
return foo;
|
|
|
|
return CreateFallbackFooTask(std::move(split.second));
|
|
}
|
|
```
|
|
|
|
While it is best to use a single callback to report success/failure, some APIs
|
|
already take multiple callbacks. `base::SplitOnceCallback()` can be used to
|
|
split a completion callback and help in such a case:
|
|
|
|
```cpp
|
|
using StatusCallback = base::OnceCallback<void(FooStatus)>;
|
|
void DoOperation(StatusCallback done_cb) {
|
|
std::pair<StatusCallback, StatusCallback> split
|
|
= base::SplitOnceCallback(std::move(done_cb));
|
|
|
|
InnerWork(BindOnce(std::move(split.first), STATUS_OK),
|
|
BindOnce(std::move(split.second), STATUS_ABORTED));
|
|
}
|
|
|
|
void InnerWork(base::OnceClosure work_done_cb,
|
|
base::OnceClosure work_aborted_cb);
|
|
```
|
|
|
|
### BarrierCallback<T>
|
|
|
|
Sometimes you might need to request data from several sources, then do something
|
|
with the collective results once all data is available. You can do this with a
|
|
`BarrierCallback<T>`. The `BarrierCallback<T>` is created with two parameters:
|
|
|
|
- `num_callbacks`: The number of times the `BarrierCallback` can be run, each
|
|
time being passed an object of type T.
|
|
- `done_callback`: This will be run once the `BarrierCallback` has been run
|
|
`num_callbacks` times.
|
|
|
|
The `done_callback` will receive a `std::vector<T>` containing the
|
|
`num_callbacks` parameters passed in the respective `Run` calls. The order of
|
|
`Ts` in the `vector` is unspecified.
|
|
|
|
Note that
|
|
|
|
- barrier callback must not be run more than `num_callback` times,
|
|
- `done_callback` will be called on the same thread as the final call to the
|
|
barrier callback. `done_callback` will also be cleared on the same thread.
|
|
|
|
Example:
|
|
|
|
```cpp
|
|
void Merge(const std::vector<Data>& data);
|
|
|
|
void Collect(base::OnceCallback<void(Data)> collect_and_merge) {
|
|
// Do something, probably asynchronously, and at some point:
|
|
std::move(collect_and_merge).Run(data);
|
|
}
|
|
|
|
CollectAndMerge() {
|
|
const auto collect_and_merge =
|
|
base::BarrierCallback<Data>(sources_.size(), base::BindOnce(&Merge));
|
|
for (const auto& source : sources_) {
|
|
// Copy the barrier callback for asynchronous data collection.
|
|
// Once all sources have called `collect_and_merge` with their respective
|
|
// data, |Merge| will be called with a vector of the collected data.
|
|
source.Collect(collect_and_merge);
|
|
}
|
|
}
|
|
```
|
|
|
|
## Quick reference for basic stuff
|
|
|
|
### Binding A Bare Function
|
|
|
|
```cpp
|
|
int Return5() { return 5; }
|
|
base::OnceCallback<int()> func_cb = base::BindOnce(&Return5);
|
|
LOG(INFO) << std::move(func_cb).Run(); // Prints 5.
|
|
```
|
|
|
|
```cpp
|
|
int Return5() { return 5; }
|
|
base::RepeatingCallback<int()> func_cb = base::BindRepeating(&Return5);
|
|
LOG(INFO) << func_cb.Run(); // Prints 5.
|
|
```
|
|
|
|
### Binding A Captureless Lambda
|
|
|
|
```cpp
|
|
base::RepeatingCallback<int()> lambda_cb = base::BindRepeating([] { return 4; });
|
|
LOG(INFO) << lambda_cb.Run(); // Print 4.
|
|
|
|
base::OnceCallback<int()> lambda_cb2 = base::BindOnce([] { return 3; });
|
|
LOG(INFO) << std::move(lambda_cb2).Run(); // Print 3.
|
|
|
|
base::OnceCallback<int()> lambda_cb3 = base::BindOnce([] { return 2; });
|
|
base::OnceCallback<int(base::OnceCallback<int()>)> lambda_cb4 =
|
|
base::BindOnce(
|
|
[](base::OnceCallback<int()> callback) {
|
|
return std::move(callback).Run(); },
|
|
std::move(lambda_cb3));
|
|
LOG(INFO) << std::move(lambda_cb4).Run(); // Print 2.
|
|
|
|
```
|
|
|
|
### Binding A Capturing Lambda (In Tests)
|
|
|
|
When writing tests, it is often useful to capture arguments that need to be
|
|
modified in a callback.
|
|
|
|
``` cpp
|
|
#include "base/test/bind.h"
|
|
|
|
int i = 2;
|
|
base::RepeatingCallback<void()> lambda_cb = base::BindLambdaForTesting([&]() { i++; });
|
|
lambda_cb.Run();
|
|
LOG(INFO) << i; // Print 3;
|
|
```
|
|
|
|
### Binding A Class Method
|
|
|
|
The first argument to bind is the member function to call, the second is the
|
|
object on which to call it.
|
|
|
|
```cpp
|
|
class Ref : public base::RefCountedThreadSafe<Ref> {
|
|
public:
|
|
int Foo() { return 3; }
|
|
};
|
|
scoped_refptr<Ref> ref = new Ref();
|
|
base::RepeatingCallback<void()> ref_cb = base::BindRepeating(&Ref::Foo, ref);
|
|
LOG(INFO) << ref_cb.Run(); // Prints out 3.
|
|
```
|
|
|
|
By default the object must support RefCounted or you will get a compiler
|
|
error. If you're passing between threads, be sure it's RefCountedThreadSafe! See
|
|
"Advanced binding of member functions" below if you don't want to use reference
|
|
counting.
|
|
|
|
### Running A Callback
|
|
|
|
Callbacks can be run with their `Run` method, which has the same signature as
|
|
the template argument to the callback. Note that `base::OnceCallback::Run`
|
|
consumes the callback object and can only be invoked on a callback rvalue.
|
|
|
|
```cpp
|
|
void DoSomething(const base::RepeatingCallback<void(int, std::string)>& callback) {
|
|
callback.Run(5, "hello");
|
|
}
|
|
|
|
void DoSomethingOther(base::OnceCallback<void(int, std::string)> callback) {
|
|
std::move(callback).Run(5, "hello");
|
|
}
|
|
```
|
|
|
|
RepeatingCallbacks can be run more than once (they don't get deleted or marked
|
|
when run). However, this precludes using `base::Passed` (see below).
|
|
|
|
```cpp
|
|
void DoSomething(const base::RepeatingCallback<double(double)>& callback) {
|
|
double myresult = callback.Run(3.14159);
|
|
myresult += callback.Run(2.71828);
|
|
}
|
|
```
|
|
|
|
If running a callback could result in its own destruction (e.g., if the callback
|
|
recipient deletes the object the callback is a member of), the callback should
|
|
be moved or copied onto the stack before it can be safely invoked. (Note that
|
|
this is only an issue for RepeatingCallbacks, because a OnceCallback always has
|
|
to be moved for execution.)
|
|
|
|
```cpp
|
|
void Foo::RunCallback() {
|
|
std::move(&foo_deleter_callback_).Run();
|
|
}
|
|
```
|
|
|
|
### Creating a Callback That Does Nothing
|
|
|
|
Sometimes you need a callback that does nothing when run (e.g. test code that
|
|
doesn't care to be notified about certain types of events). It may be tempting
|
|
to pass a default-constructed callback of the right type:
|
|
|
|
```cpp
|
|
using MyCallback = base::OnceCallback<void(bool arg)>;
|
|
void MyFunction(MyCallback callback) {
|
|
std::move(callback).Run(true); // Uh oh...
|
|
}
|
|
...
|
|
MyFunction(MyCallback()); // ...this will crash when Run()!
|
|
```
|
|
|
|
Default-constructed callbacks are null, and thus cannot be Run(). Instead, use
|
|
`base::DoNothing()`:
|
|
|
|
```cpp
|
|
...
|
|
MyFunction(base::DoNothing()); // Can be Run(), will no-op
|
|
```
|
|
|
|
`base::DoNothing()` can be passed for any OnceCallback or RepeatingCallback that
|
|
returns void.
|
|
|
|
Implementation-wise, `base::DoNothing()` is actually a functor which produces a
|
|
callback from `operator()`. This makes it unusable when trying to bind other
|
|
arguments to it. Normally, the only reason to bind arguments to DoNothing() is
|
|
to manage object lifetimes, and in these cases, you should strive to use idioms
|
|
like DeleteSoon(), ReleaseSoon(), or RefCountedDeleteOnSequence instead. If you
|
|
truly need to bind an argument to DoNothing(), or if you need to explicitly
|
|
create a callback object (because implicit conversion through operator()() won't
|
|
compile), you can instantiate directly:
|
|
|
|
```cpp
|
|
// Binds |foo_ptr| to a no-op OnceCallback takes a scoped_refptr<Foo>.
|
|
// ANTIPATTERN WARNING: This should likely be changed to ReleaseSoon()!
|
|
base::BindOnce(base::DoNothingAs<void(scoped_refptr<Foo>)>(), foo_ptr);
|
|
```
|
|
|
|
### Passing Unbound Input Parameters
|
|
|
|
Unbound parameters are specified at the time a callback is `Run()`. They are
|
|
specified in the `base::{Once, Repeating}Callback` template type:
|
|
|
|
```cpp
|
|
void MyFunc(int i, const std::string& str) {}
|
|
base::RepeatingCallback<void(int, const std::string&)> cb = base::BindRepeating(&MyFunc);
|
|
cb.Run(23, "hello, world");
|
|
```
|
|
|
|
### Passing Bound Input Parameters
|
|
|
|
Bound parameters are specified when you create the callback as arguments to
|
|
`base::Bind{Once, Repeating}()`. They will be passed to the function and the `Run()`ner of the
|
|
callback doesn't see those values or even know that the function it's calling.
|
|
|
|
```cpp
|
|
void MyFunc(int i, const std::string& str) {}
|
|
base::RepeatingCallback<void()> cb = base::BindRepeating(&MyFunc, 23, "hello world");
|
|
cb.Run();
|
|
```
|
|
|
|
As described earlier, a callback with no unbound input parameters
|
|
(`base::RepeatingCallback<void()>`) is called a `base::RepeatingClosure`. So we
|
|
could have also written:
|
|
|
|
```cpp
|
|
base::RepeatingClosure cb = base::BindRepeating(&MyFunc, 23, "hello world");
|
|
```
|
|
|
|
When calling member functions, bound parameters just go after the object
|
|
pointer.
|
|
|
|
```cpp
|
|
base::RepeatingClosure cb = base::BindRepeating(&MyClass::MyFunc, this, 23, "hello world");
|
|
```
|
|
|
|
### Partial Binding Of Parameters
|
|
|
|
You can specify some parameters when you create the callback, and specify the
|
|
rest when you execute the callback.
|
|
|
|
When calling a function bound parameters are first, followed by unbound
|
|
parameters.
|
|
|
|
```cpp
|
|
void ReadIntFromFile(const std::string& filename,
|
|
base::OnceCallback<void(int)> on_read);
|
|
|
|
void DisplayIntWithPrefix(const std::string& prefix, int result) {
|
|
LOG(INFO) << prefix << result;
|
|
}
|
|
|
|
void AnotherFunc(const std::string& file) {
|
|
ReadIntFromFile(file, base::BindOnce(&DisplayIntWithPrefix, "MyPrefix: "));
|
|
};
|
|
```
|
|
|
|
This technique is known as [partial
|
|
application](http://en.wikipedia.org/wiki/Partial_application). It should be
|
|
used in lieu of creating an adapter class that holds the bound arguments. Notice
|
|
also that the `"MyPrefix: "` argument is actually a `const char*`, while
|
|
`DisplayIntWithPrefix` actually wants a `const std::string&`. Like normal
|
|
function dispatch, `base::Bind`, will coerce parameter types if possible.
|
|
|
|
### Avoiding Copies With Callback Parameters
|
|
|
|
A parameter of `base::BindRepeating()` or `base::BindOnce()` is moved into its
|
|
internal storage if it is passed as a rvalue.
|
|
|
|
```cpp
|
|
std::vector<int> v = {1, 2, 3};
|
|
// |v| is moved into the internal storage without copy.
|
|
base::BindOnce(&Foo, std::move(v));
|
|
```
|
|
|
|
```cpp
|
|
// The vector is moved into the internal storage without copy.
|
|
base::BindOnce(&Foo, std::vector<int>({1, 2, 3}));
|
|
```
|
|
|
|
Arguments bound with `base::BindOnce()` are always moved, if possible, to the
|
|
target function.
|
|
A function parameter that is passed by value and has a move constructor will be
|
|
moved instead of copied.
|
|
This makes it easy to use move-only types with `base::BindOnce()`.
|
|
|
|
In contrast, arguments bound with `base::BindRepeating()` are only moved to the
|
|
target function if the argument is bound with `base::Passed()`.
|
|
|
|
**DANGER**:
|
|
A `base::RepeatingCallback` can only be run once if arguments were bound with
|
|
`base::Passed()`.
|
|
For this reason, avoid `base::Passed()`.
|
|
If you know a callback will only be called once, prefer to refactor code to
|
|
work with `base::OnceCallback` instead.
|
|
|
|
Avoid using `base::Passed()` with `base::BindOnce()`, as `std::move()` does the
|
|
same thing and is more familiar.
|
|
|
|
```cpp
|
|
void Foo(std::unique_ptr<int>) {}
|
|
auto p = std::make_unique<int>(42);
|
|
|
|
// |p| is moved into the internal storage of BindOnce(), and moved out to |Foo|.
|
|
base::BindOnce(&Foo, std::move(p));
|
|
base::BindRepeating(&Foo, base::Passed(&p)); // Ok, but subtle.
|
|
base::BindRepeating(&Foo, base::Passed(std::move(p))); // Ok, but subtle.
|
|
```
|
|
|
|
## Quick reference for advanced binding
|
|
|
|
### Binding A Class Method With Weak Pointers
|
|
|
|
Callbacks to a class method may be bound using a weak pointer as the receiver.
|
|
A callback bound using a weak pointer receiver will be automatically cancelled
|
|
(calling `Run()` becomes a no-op) if the weak pointer is invalidated, e.g. its
|
|
associated class instance is destroyed.
|
|
|
|
The most common way to use this pattern is by embedding a `base::WeakPtrFactory`
|
|
field, e.g.:
|
|
|
|
```cpp
|
|
class MyClass {
|
|
public:
|
|
MyClass();
|
|
|
|
void Foo();
|
|
|
|
private:
|
|
std::string data_;
|
|
|
|
// Chrome's compiler toolchain enforces that any `WeakPtrFactory`
|
|
// fields are declared last, to avoid destruction ordering issues.
|
|
base::WeakPtrFactory<MyClass> weak_factory_{this};
|
|
};
|
|
```
|
|
|
|
Then use `base::WeakPtrFactory<T>::GetWeakPtr()` as the receiver when
|
|
binding a callback:
|
|
|
|
```cpp
|
|
base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
|
|
FROM_HERE,
|
|
base::BindOnce(&MyClass::Foo, weak_factory_.GetWeakPtr());
|
|
```
|
|
|
|
If `this` is destroyed before the posted callback runs, the callback will
|
|
simply become a no-op when run, rather than being a use-after-free bug on
|
|
the destroyed `MyClass` instance.
|
|
|
|
**Sequence safety**
|
|
|
|
Class method callbacks bound to `base::WeakPtr`s must be run on the same
|
|
sequence on which the object will be destroyed to avoid potential races
|
|
between object destruction and callback execution. The same caveat applies if
|
|
a class manually invalidates live `base::WeakPtr`s with
|
|
`base::WeakPtrFactory<T>::InvalidateWeakPtrs()`.
|
|
|
|
### Binding A Class Method With Manual Lifetime Management
|
|
|
|
If a callback bound to a class method does not need cancel-on-destroy
|
|
semantics (because there is some external guarantee that the class instance will
|
|
always be live when running the callback), then use:
|
|
|
|
```cpp
|
|
// base::Unretained() is safe since `this` joins `background_thread_` in the
|
|
// destructor.
|
|
background_thread_->PostTask(
|
|
FROM_HERE, base::BindOnce(&MyClass::Foo, base::Unretained(this)));
|
|
```
|
|
|
|
It is often a good idea to add a brief comment to explain why
|
|
`base::Unretained()` is safe in this context; if nothing else, for future code
|
|
archaeologists trying to fix a use-after-free bug.
|
|
|
|
An alternative is `base::WeakPtrFactory<T>::GetSafeRef()`:
|
|
|
|
```cpp
|
|
background_thread_->PostTask(
|
|
FROM_HERE, base::BindOnce(&MyClass::Foo, weak_factory_.GetSafeRef());
|
|
```
|
|
|
|
Similar to `base::Unretained()`, this disables cancel-on-destroy semantics;
|
|
unlike `base::Unretained()`, this is guaranteed to terminate safely if the
|
|
lifetime expectations are violated.
|
|
|
|
### Binding A Class Method And Having The Callback Own The Class
|
|
|
|
```cpp
|
|
MyClass* myclass = new MyClass;
|
|
base::BindOnce(&MyClass::Foo, base::Owned(myclass));
|
|
```
|
|
|
|
The object will be deleted when the callback is destroyed, even if it's not run
|
|
(like if you post a task during shutdown). Potentially useful for "fire and
|
|
forget" cases.
|
|
|
|
Smart pointers (e.g. `std::unique_ptr<>`) are also supported as the receiver.
|
|
|
|
```cpp
|
|
std::unique_ptr<MyClass> myclass(new MyClass);
|
|
base::BindOnce(&MyClass::Foo, std::move(myclass));
|
|
```
|
|
|
|
### Ignoring Return Values
|
|
|
|
Sometimes you want to call a function that returns a value in a callback that
|
|
doesn't expect a return value.
|
|
|
|
```cpp
|
|
int DoSomething(int arg) {
|
|
cout << arg << endl;
|
|
return arg;
|
|
}
|
|
base::RepeatingCallback<void(int)> cb =
|
|
base::BindRepeating(IgnoreResult(&DoSomething));
|
|
```
|
|
|
|
Similarly, you may want to use an existing callback that returns a value in a
|
|
place that expects a void return type.
|
|
|
|
```cpp
|
|
base::RepeatingCallback<int()> cb = base::BindRepeating([](){ return 5; });
|
|
base::RepeatingClosure void_cb = base::BindRepeating(base::IgnoreResult(cb));
|
|
```
|
|
|
|
### Ignoring Arguments Values
|
|
|
|
Sometimes you want to use a function that takes fewer arguments than the
|
|
designated callback type expects. The extra arguments can be ignored as long
|
|
as they are leading.
|
|
|
|
```cpp
|
|
void LogError(char* error_message) {
|
|
if (error_message)
|
|
cout << "Log: " << error_message << endl;
|
|
}
|
|
base::RepeatingCallback<void(int, char*)> cb =
|
|
base::IgnoreArgs<int>(base::BindRepeating(&LogError));
|
|
cb.Run(42, nullptr);
|
|
```
|
|
|
|
Note in the example above that the type(s) passed to `IgnoreArgs` represent
|
|
the additional prepended parameters (those which will be "ignored"). The other
|
|
arguments to `cb` are inferred from the callback that is being wrapped.
|
|
|
|
`IgnoreArgs` can be used to adapt a closure to a callback, ignoring all the
|
|
arguments that are eventually passed:
|
|
|
|
```cpp
|
|
base::OnceClosure closure = base::BindOnce([](){ cout << "Hello!" << endl; });
|
|
base::OnceCallback<void(int)> int_cb =
|
|
base::IgnoreArgs<int>(std::move(closure));
|
|
```
|
|
|
|
## Quick reference for binding parameters to BindOnce() and BindRepeating()
|
|
|
|
Bound parameters are specified as arguments to `base::Bind{Once, Repeating}()`
|
|
and are passed to the functions.
|
|
|
|
### Passing Parameters Owned By The Callback
|
|
|
|
```cpp
|
|
void Foo(int* arg) { cout << *arg << endl; }
|
|
int* pn = new int(1);
|
|
base::RepeatingClosure foo_callback = base::BindRepeating(&foo, base::Owned(pn));
|
|
```
|
|
|
|
The parameter will be deleted when the callback is destroyed, even if it's not
|
|
run (like if you post a task during shutdown).
|
|
|
|
### Passing Parameters As A unique_ptr
|
|
|
|
```cpp
|
|
void TakesOwnership(std::unique_ptr<Foo> arg) {}
|
|
auto f = std::make_unique<Foo>();
|
|
// f becomes null during the following call.
|
|
base::OnceClosure cb = base::BindOnce(&TakesOwnership, std::move(f));
|
|
```
|
|
|
|
Ownership of the parameter will be with the callback until the callback is run,
|
|
and then ownership is passed to the callback function. This means the callback
|
|
can only be run once. If the callback is never run, it will delete the object
|
|
when it's destroyed.
|
|
|
|
### Passing Parameters As A scoped_refptr
|
|
|
|
```cpp
|
|
void TakesOneRef(scoped_refptr<Foo> arg) {}
|
|
scoped_refptr<Foo> f(new Foo);
|
|
base::RepeatingClosure cb = base::BindRepeating(&TakesOneRef, f);
|
|
```
|
|
|
|
This should "just work." The closure will take a reference as long as it is
|
|
alive, and another reference will be taken for the called function.
|
|
|
|
```cpp
|
|
void DontTakeRef(Foo* arg) {}
|
|
scoped_refptr<Foo> f(new Foo);
|
|
base::RepeatingClosure cb = base::BindRepeating(&DontTakeRef, base::RetainedRef(f));
|
|
```
|
|
|
|
`base::RetainedRef` holds a reference to the object and passes a raw pointer to
|
|
the object when the Callback is run.
|
|
|
|
### Binding Const Reference Parameters
|
|
|
|
If the callback function takes a const reference parameter then the value is
|
|
*copied* when bound unless `std::ref` or `std::cref` is used. Example:
|
|
|
|
```cpp
|
|
void foo(const int& arg) { printf("%d %p\n", arg, &arg); }
|
|
int n = 1;
|
|
base::OnceClosure has_copy = base::BindOnce(&foo, n);
|
|
base::OnceClosure has_ref = base::BindOnce(&foo, std::cref(n));
|
|
n = 2;
|
|
foo(n); // Prints "2 0xaaaaaaaaaaaa"
|
|
std::move(has_copy).Run(); // Prints "1 0xbbbbbbbbbbbb"
|
|
std::move(has_ref).Run(); // Prints "2 0xaaaaaaaaaaaa"
|
|
```
|
|
|
|
Normally parameters are copied in the closure. **DANGER**: `std::ref` and
|
|
`std::cref` store a (const) reference instead, referencing the original
|
|
parameter. This means that you must ensure the object outlives the callback!
|
|
|
|
### Binding Non-Const Reference Parameters
|
|
|
|
If the callback function takes a non-const reference then the bind statement
|
|
must specify what behavior is desired. If a reference that can mutate the
|
|
original value is desired then `std::ref` is used. If the callback should take
|
|
ownership of the value, either by making a copy or moving an existing value,
|
|
then `base::OwnedRef` is used. If neither is used the bind statement will fail
|
|
to compile. Example:
|
|
|
|
```cpp
|
|
void foo(int& arg) {
|
|
printf("%d\n", arg);
|
|
++arg;
|
|
}
|
|
|
|
int n = 0;
|
|
base::RepeatingClosure has_ref = base::BindRepeating(&foo, std::ref(n));
|
|
base::RepeatingClosure has_copy = base::BindRepeating(&foo, base::OwnedRef(n));
|
|
|
|
foo(n); // Prints "0"
|
|
has_ref.Run(); // Prints "1"
|
|
has_ref.Run(); // Prints "2"
|
|
foo(n); // Prints "3"
|
|
|
|
has_copy.Run(); // Prints "0"
|
|
has_copy.Run(); // Prints "1"
|
|
|
|
// This will fail to compile.
|
|
base::RepeatingClosure cb = base::BindRepeating(&foo, n);
|
|
```
|
|
|
|
Normally parameters are copied in the closure. **DANGER**: `std::ref` stores a
|
|
reference instead, referencing the original parameter. This means that you must
|
|
ensure the object outlives the callback!
|
|
|
|
If the callback function has an output reference parameter but the output value
|
|
isn't needed then `base::OwnedRef()` is a convenient way to handle it. The
|
|
callback owned value will be mutated by the callback function and then deleted
|
|
along with the callback. Example:
|
|
|
|
```cpp
|
|
bool Compute(size_t index, int& output);
|
|
|
|
// The `output` parameter isn't important for the callback, it only cares about
|
|
// the return value.
|
|
base::OnceClosure cb = base::BindOnce(&Compute, index, base::OwnedRef(0));
|
|
bool success = std::move(cb).Run();
|
|
```
|
|
|
|
## Implementation notes
|
|
|
|
### Where Is This Design From:
|
|
|
|
The design is heavily influenced by C++'s `tr1::function` / `tr1::bind`, and by
|
|
the "Google Callback" system used inside Google.
|
|
|
|
### Customizing the behavior
|
|
|
|
There are several injection points that controls binding behavior from outside
|
|
of its implementation.
|
|
|
|
```cpp
|
|
namespace base {
|
|
|
|
template <typename Receiver>
|
|
struct IsWeakReceiver {
|
|
static constexpr bool value = false;
|
|
};
|
|
|
|
template <typename Obj>
|
|
struct UnwrapTraits {
|
|
template <typename T>
|
|
T&& Unwrap(T&& obj) {
|
|
return std::forward<T>(obj);
|
|
}
|
|
};
|
|
|
|
} // namespace base
|
|
```
|
|
|
|
If `base::IsWeakReceiver<Receiver>::value` is true on a receiver of a method,
|
|
`base::Bind` checks if the receiver is evaluated to true and cancels the invocation
|
|
if it's evaluated to false. You can specialize `base::IsWeakReceiver` to make
|
|
an external smart pointer as a weak pointer.
|
|
|
|
`base::UnwrapTraits<BoundObject>::Unwrap()` is called for each bound argument
|
|
right before the callback calls the target function. You can specialize this to
|
|
define an argument wrapper such as `base::Unretained`, `base::Owned`,
|
|
`base::RetainedRef` and `base::Passed`.
|
|
|
|
### How The Implementation Works:
|
|
|
|
There are three main components to the system:
|
|
1) The `base::{Once, Repeating}Callback<>` classes.
|
|
2) The `base::BindOnce() and base::BindRepeating()` functions.
|
|
3) The arguments wrappers (e.g., `base::Unretained()` and `base::Owned()`).
|
|
|
|
The Callback classes represent a generic function pointer. Internally, it
|
|
stores a refcounted piece of state that represents the target function and all
|
|
its bound parameters. The `base::{Once, Repeating}Callback` constructor takes a
|
|
`base::BindStateBase*`, which is upcasted from a `base::BindState<>`. In the
|
|
context of the constructor, the static type of this `base::BindState<>` pointer
|
|
uniquely identifies the function it is representing, all its bound parameters,
|
|
and a `Run()` method that is capable of invoking the target.
|
|
|
|
base::BindOnce() or base::BindRepeating() creates the `base::BindState<>` that
|
|
has the full static type, and erases the target function type as well as the
|
|
types of the bound parameters. It does this by storing a pointer to the specific
|
|
`Run()` function, and upcasting the state of `base::BindState<>*` to a
|
|
`base::BindStateBase*`. This is safe as long as this `BindStateBase` pointer is
|
|
only used with the stored `Run()` pointer.
|
|
|
|
These bind functions, along with a set of internal templates, are responsible
|
|
for
|
|
|
|
- Unwrapping the function signature into return type, and parameters
|
|
- Determining the number of parameters that are bound
|
|
- Creating the BindState storing the bound parameters
|
|
- Performing compile-time asserts to avoid error-prone behavior
|
|
- Returning a `Callback<>` with an arity matching the number of unbound
|
|
parameters and that knows the correct refcounting semantics for the
|
|
target object if we are binding a method.
|
|
|
|
The `base::Bind` functions do the above using type-inference and variadic
|
|
templates.
|
|
|
|
By default `base::Bind{Once, Repeating}()` will store copies of all bound parameters, and
|
|
attempt to refcount a target object if the function being bound is a class
|
|
method. These copies are created even if the function takes parameters as const
|
|
references. (Binding to non-const references is forbidden, see bind.h.)
|
|
|
|
To change this behavior, we introduce a set of argument wrappers (e.g.,
|
|
`base::Unretained()`). These are simple container templates that are passed by
|
|
value, and wrap a pointer to argument. Each helper has a comment describing it
|
|
in base/functional/bind.h.
|
|
|
|
These types are passed to the `Unwrap()` functions to modify the behavior of
|
|
`base::Bind{Once, Repeating}()`. The `Unwrap()` functions change behavior by doing partial
|
|
specialization based on whether or not a parameter is a wrapper type.
|
|
|
|
`base::Unretained()` is specific to Chromium.
|
|
|
|
### Missing Functionality
|
|
- Binding arrays to functions that take a non-const pointer.
|
|
Example:
|
|
```cpp
|
|
void Foo(const char* ptr);
|
|
void Bar(char* ptr);
|
|
base::BindOnce(&Foo, "test");
|
|
base::BindOnce(&Bar, "test"); // This fails because ptr is not const.
|
|
```
|
|
- In case of partial binding of parameters a possibility of having unbound
|
|
parameters before bound parameters. Example:
|
|
```cpp
|
|
void Foo(int x, bool y);
|
|
base::BindOnce(&Foo, _1, false); // _1 is a placeholder.
|
|
```
|
|
|
|
If you are thinking of forward declaring `base::{Once, Repeating}Callback` in
|
|
your own header file, please include "base/functional/callback_forward.h"
|
|
instead.
|