Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to combine the use of std::bind with std::shared_ptr

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.

like image 705
Stephane Rolland Avatar asked Nov 07 '12 15:11

Stephane Rolland


2 Answers

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

like image 72
PiotrNycz Avatar answered Oct 22 '22 14:10

PiotrNycz


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.

like image 45
Mateusz Pusz Avatar answered Oct 22 '22 14:10

Mateusz Pusz