0

I am attempting to come up with a solution for move-capturing a std::unique_ptr into a lambda, creating an std::function<void()> from that lambda, moving that function into a queue, then later moving the function out of the queue to execute it.

Here is my test code:

#include <functional>
#include <iostream>
#include <memory>

using fn_t  = std::function<void()>;

struct Foo {
    Foo(int a, int b) : a(a), b(b) {
        std::cout << "Foo::Foo()" << std::endl;
    }
    ~Foo() {
        std::cout << "Foo::~Foo()" << std::endl;
    }
    
    int a;
    int b;
};

static fn_t fnQueue;

void queue(fn_t fn) {
    fnQueue = std::move(fn);
}

void dequeue() {
    fnQueue();
    fnQueue = fn_t();
}

template <typename FN>
inline void invoke(FN&& fn) {
    queue(std::forward<FN>(fn));
    dequeue();
}

int main() {
    std::unique_ptr<Foo> ptr(new Foo{10, 11});
    
    invoke([ptr = std::move(ptr)](){
        std::cout << "a=" << ptr->a << ", b=" << ptr->b << std::endl;
    });
    
    return 0;
}

Which results in the following compile-time error:

In file included from C:/Program Files/mingw-w64/x86_64-8.1.0-posix-seh-rt_v6-rev0/mingw64/lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++/functional:59,
                 from lambda_unique_ptr.cpp:1:
C:/Program Files/mingw-w64/x86_64-8.1.0-posix-seh-rt_v6-rev0/mingw64/lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++/bits/std_function.h: In instantiation of 'static void std::_Function_base::_Base_manager<_Functor>::_M_clone(std::_Any_data&, const std::_Any_data&, std::false_type) [with _Functor = main()::<lambda()>; std::false_type = std::integral_constant<bool, false>]':
C:/Program Files/mingw-w64/x86_64-8.1.0-posix-seh-rt_v6-rev0/mingw64/lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++/bits/std_function.h:208:16:   required from 'static bool std::_Function_base::_Base_manager<_Functor>::_M_manager(std::_Any_data&, const std::_Any_data&, std::_Manager_operation) [with _Functor = main()::<lambda()>]'
C:/Program Files/mingw-w64/x86_64-8.1.0-posix-seh-rt_v6-rev0/mingw64/lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++/bits/std_function.h:676:19:   required from 'std::function<_Res(_ArgTypes ...)>::function(_Functor) [with _Functor = main()::<lambda()>; <template-parameter-2-2> = void; <template-parameter-2-3> = void; _Res = void; _ArgTypes = {}]'
lambda_unique_ptr.cpp:41:6:   required from here
C:/Program Files/mingw-w64/x86_64-8.1.0-posix-seh-rt_v6-rev0/mingw64/lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++/bits/std_function.h:173:6: error: use of deleted function 'main()::<lambda()>::<lambda>(const main()::<lambda()>&)'
      new _Functor(*__source._M_access<_Functor*>());
      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
lambda_unique_ptr.cpp:39:38: note: 'main()::<lambda()>::<lambda>(const main()::<lambda()>&)' is implicitly deleted because the default definition would be ill-formed:
     invoke(fn_t([ptr = std::move(ptr)](){
                                      ^
lambda_unique_ptr.cpp:39:38: error: use of deleted function 'std::unique_ptr<_Tp, _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = Foo; _Dp = std::default_delete<Foo>]'
In file included from C:/Program Files/mingw-w64/x86_64-8.1.0-posix-seh-rt_v6-rev0/mingw64/lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++/memory:80,
                 from lambda_unique_ptr.cpp:3:
C:/Program Files/mingw-w64/x86_64-8.1.0-posix-seh-rt_v6-rev0/mingw64/lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++/bits/unique_ptr.h:394:7: note: declared here
       unique_ptr(const unique_ptr&) = delete;

Any ideas how to make this work?

Patrick Wright
  • 995
  • 3
  • 11
  • 1
    `std::function` requires the functor to be copy constructible and `std::unique_ptr`'s copy constructor is `delete`d. – Ted Lyngmo Nov 09 '21 at 22:10

0 Answers0