13

I need to do something like this more than often:

AsyncOperation * pAsyncOperation = new AsyncOperation();
auto bindOperation = std::bind(&AsyncOperation::operator(), std::ref(*pAsyncOperation));
std::thread thread(bindOperation );
thread.join();

with AsyncOperation being any custom class implementing operator() (also known as function object).

Is it possible to indicate to the std::bind to use a std::shared_ptr instead of a std::ref ? This would prevent memory leaks, without my needing to keep a reference on pAsyncOperation, and would delete the AsyncOperation automatically at the end of the thread, that is the end of this asynchronous task.

EDIT: I don't always have access to std::thread, the thread library can be boost::thread or even any other platform dependent threads. And by consequence, not access to std::async.

My main issue is to have a notion of ownership in the std::bind.

Stephane Rolland
  • 38,876
  • 35
  • 121
  • 169
  • 1
    Have you tried to use `std::shared_ptr`? Looks that compiles without problems: http://liveworkspace.org/code/1e83d9698703711b7ed2ce0d44cf86f2 – PiotrNycz Nov 07 '12 at 15:48
  • 2
    What you need to know is that `std::bind` stores bound arguments by value (i.e., as passed), therefore, if you pass an owning pointer by value as one of the parameter, that pointer gets 'copied' into the resulting functor, hence, holding ownership even after the original `shared_ptr` goes out of scope. – haelix Mar 10 '15 at 11:38

2 Answers2

15

This works:

struct AsyncOperation {
    void operator()()
    {
        std::cout << "AsyncOperation" << '\n';
    }
};

int main() {
  std::shared_ptr<AsyncOperation>  pAsyncOperation = std::make_shared<AsyncOperation>();
  auto bindOperation = std::bind(&AsyncOperation::operator(), pAsyncOperation);
  std::thread thread(bindOperation );
  thread.join();
}

See: http://liveworkspace.org/code/4bc81bb6c31ba7b2bdeb79ea0e02bb89

PiotrNycz
  • 23,099
  • 7
  • 66
  • 112
  • Do you need to use `make_shared`, or will `std::shared_ptr pAsyncOperation( new AsyncOperation() );` do? – akaltar Jul 26 '16 at 00:35
  • 1
    @akaltar you can use both "styles" - but make_shared is better - read: https://stackoverflow.com/questions/31232146/why-is-it-better-to-use-stdmake-instead-of-the-constructor – PiotrNycz Jul 26 '16 at 12:26
8

Do you need AsyncOperation to be allocated dynamically? If not, I would do that:

auto f = std::async([]{ AsyncOperation()(); });
f.wait();

otherwise:

std::unique_ptr<AsyncOperation> op(new AsyncOperation);
auto f = std::async([&]{ (*op)(); });
f.wait();

You can of course use std::thread, but it can provide more problems (i.e. exception handling in other thread). std::bind has also its own problems and you will probably better end up with a lambda.

If you really need to pass an ownership to other thread you can also do that:

std::unique_ptr<AsyncOperation> op(new AsyncOperation);
auto f = std::async([&](std::unique_ptr<AsyncOperation> op){ (*op)(); }, std::move(op));
f.wait();

as lambdas do not support move type captures yet.

I hope that helps.

Mateusz Pusz
  • 1,363
  • 1
  • 9
  • 16