google / marl

A hybrid thread / fiber task scheduler written in C++ 11
Apache License 2.0
1.84k stars 191 forks source link

Can't capture unique_ptr in marl::schedule lambda #211

Open 123qws opened 2 years ago

123qws commented 2 years ago

Here's a simple example:

#include <iostream>
#include "marl/scheduler.h"

int main(int argc, char** argv) {
  std::unique_ptr<int> input = std::make_unique<int>(10);
  marl::schedule([=, input = std::move(input)] {
    std::cout << "input: " << *input << std::endl;
  });
}

I got the following compile error:

In file included from /usr/gcc_toolchain/lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/functional:59:
/usr/gcc_toolchain/lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/bits/std_function.h:176:10: error: call to implicitly-deleted copy constructor of '(lambda at .../test.cc:7:18)'
            new _Functor(*__source._M_access<const _Functor*>());
                ^        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/gcc_toolchain/lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/bits/std_function.h:211:8: note: in instantiation of member function 'std::_Function_base::_Base_manager<(lambda at .../test.cc:7:18)>::_M_clone' requested here
              _M_clone(__dest, __source, _Local_storage());
              ^
/usr/gcc_toolchain/lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/bits/std_function.h:677:33: note: in instantiation of member function 'std::_Function_base::_Base_manager<(lambda at .../test.cc:7:18)>::_M_manager' requested here
            _M_manager = &_My_handler::_M_manager;
                                       ^
external/marl/include/marl/scheduler.h:534:27: note: in instantiation of function template specialization 'std::function<void ()>::function<(lambda at .../test.cc:7:18), void, void>' requested here
  scheduler->enqueue(Task(std::forward<Function>(f)));
                          ^
...test.cc:7:9: note: in instantiation of function template specialization 'marl::schedule<(lambda at .../test.cc:7:18)>' requested here
  marl::schedule([=, input = std::move(input)] {
        ^
.../test.cc:7:22: note: copy constructor of '' is implicitly deleted because field '' has a deleted copy constructor
  marl::schedule([=, input = std::move(input)] {
                     ^
/usr/gcc_toolchain/lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/bits/unique_ptr.h:414:7: note: 'unique_ptr' has been explicitly marked deleted here
      unique_ptr(const unique_ptr&) = delete;
      ^
1 error generated.

The std::thread() lambda can take unique_ptr though. Any ideas? Thanks.

ben-clayton commented 2 years ago

Hi @123qws ,

Sorry for the slow reply, this slipped my radar.

Yes, this is an unfortunate consequence of marl's tasks using std::function, which in turn requires the wrapped function is CopyConstructible. A minimal example of the problem can be seen here.

I did just notice that std::packaged_task may act as a drop-in replacement that is less restrictive. Let me experiment a bit.

Cheers, Ben