z0r
z0r

Reputation: 8585

Is a capture captured even if it isn't used?

I'm using an async function that takes an object reference &foo and a callback cb as arguments. I want to prevent destruction of foo until the callback is called.

void async_thing(Foo &foo, function<void()> cb) {
    // do something asynchronously with foo
}

Is it enough to simply capture it in the callback lambda? Or does it need to be actually used in the lambda?

auto foo = make_shared<Foo>();
async_thing(*foo, [foo]() {
    cout << "Callback ran" << endl;
});

Might a compiler optimise the capture out, and delete foo prematurely?

Upvotes: 1

Views: 34

Answers (1)

spectras
spectras

Reputation: 13552

n3690, section 5.1.2

15. An entity is captured by copy if it is implicitly captured and the capture-default is = or if it is explicitly captured with a capture that does not include an &. For each entity captured by copy, an unnamed nonstatic data member is declared in the closure type.

Above which we have:

3. The type of the lambda-expression (which is also the type of the closure object) is a unique, unnamed nonunion class type — called the closure type.
[…]
An implementation may define the closure type differently from what is described below provided this does not alter the observable behavior of the program other than by changing:

  • the size and/or alignment of the closure type,
  • whether the closure type is trivially copyable (Clause 9),
  • whether the closure type is a standard-layout class (Clause 9), or
  • whether the closure type is a POD class (Clause 9).

From this I would conclude that:

  • The capture makes a shared_ptr member in the closure type.
  • The compiler is not allowed to alter that observable behavior.
  • So your pointer won't be deleted until the destructor of the closure is called.

Upvotes: 2

Related Questions