208

How do I capture by move (also known as rvalue reference) in a C++11 lambda?

I am trying to write something like this:

std::unique_ptr<int> myPointer(new int);

std::function<void(void)> example = [std::move(myPointer)]{
   *myPointer = 4;
};

7 Answers7

243

Generalized lambda capture in C++14

In C++14 we will have the so called generalized lambda capture. This enables move capture. The following will be legal code in C++14:

using namespace std;

// a unique_ptr is move-only
auto u = make_unique<some_type>( some, parameters );  

// move the unique_ptr into the lambda
go.run( [ u = move(u) ] { do_something_with( u ); } ); 

Also note if you need to move object from lambda to some other function you need to make lambda mutable.

go.run( [ u = move(u) ] mutable { do_something_with( std::move(u) ); } );

The generalized lambda capture is much more general in the sense that captured variables can be initialized with anything like so:

auto lambda = [value = 0] mutable { return ++value; };

In C++11 this is not possible yet, but with some tricks that involve helper types. Fortunately, the Clang 3.4 compiler already implements this awesome feature. The compiler will be released December 2013 or January 2014, if the recent release pace will be kept.

UPDATE: The Clang 3.4 compiler was released on 6 Jan 2014 with the said feature.

A workaround for move capture

Here's an implementation of a helper function make_rref which helps with artificial move capture

#include <cassert>
#include <memory>
#include <utility>

template <typename T>
struct rref_impl
{
    rref_impl() = delete;
    rref_impl( T && x ) : x{std::move(x)} {}
    rref_impl( rref_impl & other )
        : x{std::move(other.x)}, isCopied{true}
    {
        assert( other.isCopied == false );
    }
    rref_impl( rref_impl && other )
        : x{std::move(other.x)}, isCopied{std::move(other.isCopied)}
    {
    }
    rref_impl & operator=( rref_impl other ) = delete;
    T && move()
    {
        return std::move(x);
    }

private:
    T x;
    bool isCopied = false;
};

template<typename T> rref_impl<T> make_rref( T && x )
{
    return rref_impl<T>{ std::move(x) };
}

And here's a test case for that function that ran successfully on my gcc 4.7.3.

int main()
{
    std::unique_ptr<int> p{new int(0)};
    auto rref = make_rref( std::move(p) );
    auto lambda =
        [rref]() mutable -> std::unique_ptr<int> { return rref.move(); };
    assert(  lambda() );
    assert( !lambda() );
}

The drawback here is that lambda is copyable and when copied the assertion in the copy constructor of rref_impl fails leading to a runtime bug. The following might be a better and even more generic solution because the compiler will catch the error.

Emulating generalized lambda capture in C++11

Here's one more idea, on how to implement generalized lambda capture. The use of the function capture() (whose implementation is found further down) is as follows:

#include <cassert>
#include <memory>

int main()
{
    std::unique_ptr<int> p{new int(0)};
    auto lambda = capture( std::move(p),
        []( std::unique_ptr<int> & p ) { return std::move(p); } );
    assert(  lambda() );
    assert( !lambda() );
}

Here lambda is a functor object (almost a real lambda) which has captured std::move(p) as it is passed to capture(). The second argument of capture is a lambda which takes the captured variable as an argument. When lambda is used as a function object, then all arguments that are passed to it will be forwarded to the internal lambda as arguments after the captured variable. (In our case there are no further arguments to be forwarded). Essentially, the same as in the previous solution happens. Here's how capture is implemented:

#include <utility>

template <typename T, typename F>
class capture_impl
{
    T x;
    F f;
public:
    capture_impl( T && x, F && f )
        : x{std::forward<T>(x)}, f{std::forward<F>(f)}
    {}

    template <typename ...Ts> auto operator()( Ts&&...args )
        -> decltype(f( x, std::forward<Ts>(args)... ))
    {
        return f( x, std::forward<Ts>(args)... );
    }

    template <typename ...Ts> auto operator()( Ts&&...args ) const
        -> decltype(f( x, std::forward<Ts>(args)... ))
    {
        return f( x, std::forward<Ts>(args)... );
    }
};

template <typename T, typename F>
capture_impl<T,F> capture( T && x, F && f )
{
    return capture_impl<T,F>(
        std::forward<T>(x), std::forward<F>(f) );
}

This second solution is also cleaner, because it disables copying the lambda, if the captured type is not copyable. In the first solution that can only be checked at runtime with an assert().

DikobrAz
  • 3,557
  • 4
  • 35
  • 53
Ralph Tandetzky
  • 22,780
  • 11
  • 73
  • 120
  • I have been using this long with G++-4.8 -std=c++11, and I thought it is a C++11 feature. Now I'm used of using this and suddenly realized it is a C++14 feature... What should I do!! – RnMss Jan 29 '14 at 11:51
  • @RnMss Which feature do you mean? Generalized lambda capture? – Ralph Tandetzky Jan 29 '14 at 17:54
  • @RalphTandetzky I think so, I just checked and the version of clang bundled with XCode seems to support it too! It gives a warning that it's a C++1y extension but it does work. – Christopher Tarquini May 21 '14 at 17:07
  • @RnMss Either use a `moveCapture` wrapper to pass them as arguments (this method is used above and in Capn'Proto, a library by the creator of protobuffs) or make just accept that you require compilers that support it :P – Christopher Tarquini May 21 '14 at 17:09
  • 1
    I don't see the point of such work around when one can write this : `[&p]() mutable -> std::unique_ptr { return std::move(p); }`. Doesn't it do the same thing? – Nawaz Sep 18 '14 at 15:05
  • 12
    No, it actually is not the same thing. Example: You want to spawn a thread with a lambda which move-captures the unique pointer. The spawning function can possibly return and the unique_ptr go out of scope before the functor gets executed. Therefore, you have a dangling reference to a unique_ptr. Welcome to undefined-behavior-land. – Ralph Tandetzky Oct 08 '14 at 10:59
  • Could the `capture_impl` solution be expanded for multiple move captures by using a parameter pack instead of `T`? – Emile Cormier Feb 12 '20 at 21:28
  • To answer my own question... one possibility would be to move capture a `std::tuple`, but having to do `tuple.get<0>()`, `tuple.get<1>()` in the lambda body would be more inconvenient than separate parameters. – Emile Cormier Feb 12 '20 at 21:41
  • What types of parameters is ```do_something_with``` expecting in your example? I have a similar implementation in which ```do_something_with``` takes the type that was moved in by reference. It complains though that the type of 'u' is an initializer list. – bgura Nov 07 '20 at 04:04
  • Note that lambda without parameter clause is a c++23 feature – ManuelSchneid3r Nov 05 '22 at 12:10
82

You could also use std::bind to capture the unique_ptr:

std::function<void()> f = std::bind(
                              [] (std::unique_ptr<int>& p) { *p=4; },
                              std::move(myPointer)
                          );
marton78
  • 3,899
  • 2
  • 27
  • 38
  • 4
    Have you checked, if the code compiles? It doesn't look so to me, since firstly the variable name is missing and secondly a `unique_ptr` rvalue reference cannot bind to an `int *`. – Ralph Tandetzky Apr 04 '14 at 08:28
  • 8
    Note that in Visual Studio 2013, converting a std::bind to a std::function still results in it copying all the bound variables (`myPointer` in this case). Therefore the above code does not compile in VS2013. It woks fine in GCC 4.8 though. – Alan Dec 02 '15 at 18:07
27

You can achieve most of what you want using std::bind, like this:

std::unique_ptr<int> myPointer(new int{42});

auto lambda = std::bind([](std::unique_ptr<int>& myPointerArg){
    *myPointerArg = 4;
     myPointerArg.reset(new int{237});
}, std::move(myPointer));

The trick here is that instead of capturing your move-only object in the captures list, we make it an argument and then use partial application via std::bind to make it vanish. Note that the lambda takes it by reference, because it's actually stored in the bind object. I also added code that writes to the actual movable object, because that's something you might want to do.

In C++14, you can use generalized lambda capture to achieve the same ends, with this code:

std::unique_ptr<int> myPointer(new int{42});

auto lambda = [myPointerCapture = std::move(myPointer)]() mutable {
    *myPointerCapture = 56;
    myPointerCapture.reset(new int{237});
};

But this code doesn't buy you anything you didn't have in C++11 via std::bind. (There are some situations where generalized lambda capture is more powerful, but not in this case.)

Now there is just one problem; you wanted to put this function in a std::function, but that class requires that the function be CopyConstructible, but it isn't, it's only MoveConstructible because it's storing a std::unique_ptr which isn't CopyConstructible.

You to work around the issue with wrapper class and another level of indirection, but perhaps you don't need std::function at all. Depending on your needs, you may be able to use std::packaged_task; it'd do the same job as std::function, but it doesn't require the function to be copyable, only movable (similarly, std::packaged_task is only movable). The downside is that because it's intended to be used in conjunction with std::future, you can only call it once.

Here's a short program that shows all of these concepts.

#include <functional>   // for std::bind
#include <memory>       // for std::unique_ptr
#include <utility>      // for std::move
#include <future>       // for std::packaged_task
#include <iostream>     // printing
#include <type_traits>  // for std::result_of
#include <cstddef>

void showPtr(const char* name, const std::unique_ptr<size_t>& ptr)
{
    std::cout << "- &" << name << " = " << &ptr << ", " << name << ".get() = "
              << ptr.get();
    if (ptr)
        std::cout << ", *" << name << " = " << *ptr;
    std::cout << std::endl;
}

// If you must use std::function, but your function is MoveConstructable
// but not CopyConstructable, you can wrap it in a shared pointer.
template <typename F>
class shared_function : public std::shared_ptr<F> {
public:
    using std::shared_ptr<F>::shared_ptr;

    template <typename ...Args>
    auto operator()(Args&&...args) const
        -> typename std::result_of<F(Args...)>::type
    {
        return (*(this->get()))(std::forward<Args>(args)...);
    }
};

template <typename F>
shared_function<F> make_shared_fn(F&& f)
{
    return shared_function<F>{
        new typename std::remove_reference<F>::type{std::forward<F>(f)}};
}


int main()
{
    std::unique_ptr<size_t> myPointer(new size_t{42});
    showPtr("myPointer", myPointer);
    std::cout << "Creating lambda\n";

#if __cplusplus == 201103L // C++ 11

    // Use std::bind
    auto lambda = std::bind([](std::unique_ptr<size_t>& myPointerArg){
        showPtr("myPointerArg", myPointerArg);  
        *myPointerArg *= 56;                    // Reads our movable thing
        showPtr("myPointerArg", myPointerArg);
        myPointerArg.reset(new size_t{*myPointerArg * 237}); // Writes it
        showPtr("myPointerArg", myPointerArg);
    }, std::move(myPointer));

#elif __cplusplus > 201103L // C++14

    // Use generalized capture
    auto lambda = [myPointerCapture = std::move(myPointer)]() mutable {
        showPtr("myPointerCapture", myPointerCapture);
        *myPointerCapture *= 56;
        showPtr("myPointerCapture", myPointerCapture);
        myPointerCapture.reset(new size_t{*myPointerCapture * 237});
        showPtr("myPointerCapture", myPointerCapture);
    };

#else
    #error We need C++11
#endif

    showPtr("myPointer", myPointer);
    std::cout << "#1: lambda()\n";
    lambda();
    std::cout << "#2: lambda()\n";
    lambda();
    std::cout << "#3: lambda()\n";
    lambda();

#if ONLY_NEED_TO_CALL_ONCE
    // In some situations, std::packaged_task is an alternative to
    // std::function, e.g., if you only plan to call it once.  Otherwise
    // you need to write your own wrapper to handle move-only function.
    std::cout << "Moving to std::packaged_task\n";
    std::packaged_task<void()> f{std::move(lambda)};
    std::cout << "#4: f()\n";
    f();
#else
    // Otherwise, we need to turn our move-only function into one that can
    // be copied freely.  There is no guarantee that it'll only be copied
    // once, so we resort to using a shared pointer.
    std::cout << "Moving to std::function\n";
    std::function<void()> f{make_shared_fn(std::move(lambda))};
    std::cout << "#4: f()\n";
    f();
    std::cout << "#5: f()\n";
    f();
    std::cout << "#6: f()\n";
    f();
#endif
}

I've put a the above program on Coliru, so you can run and play with the code.

Here's some typical output...

- &myPointer = 0xbfffe5c0, myPointer.get() = 0x7ae3cfd0, *myPointer = 42
Creating lambda
- &myPointer = 0xbfffe5c0, myPointer.get() = 0x0
#1: lambda()
- &myPointerArg = 0xbfffe5b4, myPointerArg.get() = 0x7ae3cfd0, *myPointerArg = 42
- &myPointerArg = 0xbfffe5b4, myPointerArg.get() = 0x7ae3cfd0, *myPointerArg = 2352
- &myPointerArg = 0xbfffe5b4, myPointerArg.get() = 0x7ae3cfe0, *myPointerArg = 557424
#2: lambda()
- &myPointerArg = 0xbfffe5b4, myPointerArg.get() = 0x7ae3cfe0, *myPointerArg = 557424
- &myPointerArg = 0xbfffe5b4, myPointerArg.get() = 0x7ae3cfe0, *myPointerArg = 31215744
- &myPointerArg = 0xbfffe5b4, myPointerArg.get() = 0x7ae3cfd0, *myPointerArg = 3103164032
#3: lambda()
- &myPointerArg = 0xbfffe5b4, myPointerArg.get() = 0x7ae3cfd0, *myPointerArg = 3103164032
- &myPointerArg = 0xbfffe5b4, myPointerArg.get() = 0x7ae3cfd0, *myPointerArg = 1978493952
- &myPointerArg = 0xbfffe5b4, myPointerArg.get() = 0x7ae3cfe0, *myPointerArg = 751631360
Moving to std::function
#4: f()
- &myPointerArg = 0x7ae3cfd4, myPointerArg.get() = 0x7ae3cfe0, *myPointerArg = 751631360
- &myPointerArg = 0x7ae3cfd4, myPointerArg.get() = 0x7ae3cfe0, *myPointerArg = 3436650496
- &myPointerArg = 0x7ae3cfd4, myPointerArg.get() = 0x7ae3d000, *myPointerArg = 2737348608
#5: f()
- &myPointerArg = 0x7ae3cfd4, myPointerArg.get() = 0x7ae3d000, *myPointerArg = 2737348608
- &myPointerArg = 0x7ae3cfd4, myPointerArg.get() = 0x7ae3d000, *myPointerArg = 2967666688
- &myPointerArg = 0x7ae3cfd4, myPointerArg.get() = 0x7ae3cfe0, *myPointerArg = 3257335808
#6: f()
- &myPointerArg = 0x7ae3cfd4, myPointerArg.get() = 0x7ae3cfe0, *myPointerArg = 3257335808
- &myPointerArg = 0x7ae3cfd4, myPointerArg.get() = 0x7ae3cfe0, *myPointerArg = 2022178816
- &myPointerArg = 0x7ae3cfd4, myPointerArg.get() = 0x7ae3d000, *myPointerArg = 2515009536

You get to see heap locations being reused, showing that the std::unique_ptr is working properly. You also see the function itself move around when we stash it in a wrapper we feed to std::function.

If we switch to using std::packaged_task, it the last part becomes

Moving to std::packaged_task
#4: f()
- &myPointerArg = 0xbfffe590, myPointerArg.get() = 0x7ae3cfe0, *myPointerArg = 751631360
- &myPointerArg = 0xbfffe590, myPointerArg.get() = 0x7ae3cfe0, *myPointerArg = 3436650496
- &myPointerArg = 0xbfffe590, myPointerArg.get() = 0x7ae3d000, *myPointerArg = 2737348608

so we see that the function has been moved, but rather than getting moved onto the heap, it's inside the std::packaged_task that's on the stack.

Hope this helps!

Charphacy
  • 2,110
  • 1
  • 20
  • 12
7

Late, but as some people (including me) are still stuck on c++11:

To be honest, I don't really like any of the posted solutions. I'm sure they will work, but they require a lot of additional stuff and/or cryptical std::bind syntax... and I don't think that it's worth the effort for such a temporary solution which will be refactored anyway when upgrading to c++ >= 14. So I think the best solution is to avoid move capturing for c++11 completely.

Usually the simplest and best readable solution is to use std::shared_ptr, which are copyable and so the move is completely avoidable. Downside is, that it's a little less efficient, but in many cases efficiency is not so important.

// myPointer could be a parameter or something
std::unique_ptr<int> myPointer(new int);

// convert/move the unique ptr into a shared ptr
std::shared_ptr<int> mySharedPointer( std::move(myPointer) );

std::function<void(void)> = [mySharedPointer](){
   *mySharedPointer = 4;
};

// at end of scope the original mySharedPointer is destroyed,
// but the copy still lives in the lambda capture.

.

If the very rare case occurs, that it's really mandatory to move the pointer (e.g. you want to explicitly delete a pointer in a separate thread due to lengthy delete duration, or performance is absolutely crucial), that's pretty much the only case where I still use raw pointers in c++11. These are of course also copyable.

Usually I mark these rare cases with a //FIXME: to ensure that it's refactored once upgrading to c++ 14.

// myPointer could be a parameter or something
std::unique_ptr<int> myPointer(new int);

//FIXME:c++11 upgrade to new move capture on c++>=14

// "move" the pointer into a raw pointer
int* myRawPointer = myPointer.release();

// capture the raw pointer as a copy.
std::function<void(void)> = [myRawPointer](){
   std::unique_ptr<int> capturedPointer(myRawPointer);
   *capturedPointer = 4;
};

// ensure that the pointer's value is not accessible anymore after capturing
myRawPointer = nullptr;

Yes, raw pointers are pretty frowned upon these days (and not without reason), but I really think in these rare (and temporary!) cases they are the best solution.

user2328447
  • 1,807
  • 1
  • 21
  • 27
  • Thanks, using C++14 and non of the other solutions were good. Saved my day! – Yoav Sternberg Aug 02 '19 at 16:08
  • The raw pointer trick is a perfect workaround for working with [std::function](https://stackoverflow.com/questions/25421346/how-to-create-an-stdfunction-from-a-move-capturing-lambda-expression) – Matt Eding Apr 28 '21 at 21:56
3

This seems to work on gcc4.8

#include <memory>
#include <iostream>

struct Foo {};

void bar(std::unique_ptr<Foo> p) {
    std::cout << "bar\n";
}

int main() {
    std::unique_ptr<Foo> p(new Foo);
    auto f = [ptr = std::move(p)]() mutable {
        bar(std::move(ptr));
    };
    f();
    return 0;
}
andoryu-
  • 116
  • 4
2

I was looking at these answers, but I found bind hard to read and understand. So what I did was make a class that moved on copy instead. In this way, it is explicit with what it is doing.

#include <iostream>
#include <memory>
#include <utility>
#include <type_traits>
#include <functional>

namespace detail
{
    enum selection_enabler { enabled };
}

#define ENABLE_IF(...) std::enable_if_t<(__VA_ARGS__), ::detail::selection_enabler> \
                          = ::detail::enabled

// This allows forwarding an object using the copy constructor
template <typename T>
struct move_with_copy_ctor
{
    // forwarding constructor
    template <typename T2
        // Disable constructor for it's own type, since it would
        // conflict with the copy constructor.
        , ENABLE_IF(
            !std::is_same<std::remove_reference_t<T2>, move_with_copy_ctor>::value
        )
    >
    move_with_copy_ctor(T2&& object)
        : wrapped_object(std::forward<T2>(object))
    {
    }

    // move object to wrapped_object
    move_with_copy_ctor(T&& object)
        : wrapped_object(std::move(object))
    {
    }

    // Copy constructor being used as move constructor.
    move_with_copy_ctor(move_with_copy_ctor const& object)
    {
        std::swap(wrapped_object, const_cast<move_with_copy_ctor&>(object).wrapped_object);
    }

    // access to wrapped object
    T& operator()() { return wrapped_object; }

private:
    T wrapped_object;
};


template <typename T>
move_with_copy_ctor<T> make_movable(T&& object)
{
    return{ std::forward<T>(object) };
}

auto fn1()
{
    std::unique_ptr<int, std::function<void(int*)>> x(new int(1)
                           , [](int * x)
                           {
                               std::cout << "Destroying " << x << std::endl;
                               delete x;
                           });
    return [y = make_movable(std::move(x))]() mutable {
        std::cout << "value: " << *y() << std::endl;
        return;
    };
}

int main()
{
    {
        auto x = fn1();
        x();
        std::cout << "object still not deleted\n";
        x();
    }
    std::cout << "object was deleted\n";
}

The move_with_copy_ctor class and it's helper function make_movable() will work with any movable but not copyable object. To get access to the wrapped object, use the operator()().

Expected output:

value: 1
object still not deleted
value: 1
Destroying 000000DFDD172280
object was deleted

Well, the pointer address may vary. ;)

Demo

Adrian
  • 10,246
  • 4
  • 44
  • 110
1

Lambdas are just syntactic sugar for anonymous function objects. You can just declare a function-local struct and provide an operator() member:

void someFunction(std::unique_ptr<Foo> foo)
{
    struct Anonymous
    {
        std::unique_ptr<Foo> ptr;

        void operator()()
        {
            ptr->doSomething();
        }
    };

    std::function<void(void)> f = Anonymous{std::move(foo)};
}

To capture more variables, just add more member variables to the struct and initialize them when instantiating.

It's very verbose, I know. But it's a viable alternative that works in C++11 without resorting to a bunch of hacks, meta-programming, or std::bind.

A variant of this with templates can also be used in lieu of generic lambdas, but C++11 does not allow member function templates within function-local structs, so the struct has be declared in class, namespace, or global scope.

Emile Cormier
  • 28,391
  • 15
  • 94
  • 122