1

I am using a function (not mine, from a library I don't control) with a signature similar to this:

template<typename T, typename F> void do_async(T const&, F); // the second parameter is a callable 

and it usually used like this

do_async(obj, [this](){ ... }); 

I wrote a function similar to this that always uses the same callback lambda:

template<typename T> void do_async_wrapper(T obj) { do_async(obj, [this](){ ... }); } 

My problems stem from the fact that since the obj is passed as a reference, it has to be kept alive until the callback is called. My function is supposed to take care of that so the caller doesn't have to worry about object lifetime. That is why it accepts by value.
I would like to do something like this in order to keep it alive:

template<typename T> void do_async_wrapper(T obj) { do_async(obj, [this, obj{std::move(obj)}](){ ... }); } 

Obviously this wont (always) work as-is since the reference points to the function-local one which doesn't exist anymore, while the one kept alive is a (move-)copy of it.

Any suggestions?

10
  • What is do_async doing with that parameter? Are you sure it doesn't make a copy internally? Commented Jan 9, 2017 at 12:04
  • @TartanLlama Yes. The library docs specify that it is the caller's responsibility to make sure the object stays alive. Commented Jan 9, 2017 at 12:07
  • Can you link to the docs? One option would be a std::shared_ptr. Commented Jan 9, 2017 at 12:09
  • @TartanLlama That would involve allocating another object on the heap, besides the lambda object (which I am starting to think is probably unavoidable) Commented Jan 9, 2017 at 12:11
  • 1
    If the async launcher and async task both need access to the buffer, that sounds like a fairly good use-case for std::shared_ptr, even with the dynamic allocation. Commented Jan 9, 2017 at 12:15

1 Answer 1

2

As the functor is taken by value, you cannot store the object directly in the functor and pass a reference to it. You may work-around that by using smart pointer as shared_ptr:

template<typename T> void do_async_wrapper(T obj) { auto ptr = std::make_shared<T>(std::move(obj)); do_async(*ptr, [this, ptr](){ /*...*/ }); } 
Sign up to request clarification or add additional context in comments.

3 Comments

I'd be tempted by make_unique instead of make_shared, as do_async shouldn't be copying the lambda. But that requires an extra line to make it work (auto& obj_ref = *ptr;) in a defined way.
@Yakk I went with a similar solution using make_unique. I didn't need the line you show. What is the point of it?
@baruch: There are 2 problems, unspecified order between *ptr and the [ptr = std::move(ptr)], and the copy of F in do_async (which make the 2 instance of T different).

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.