5

I have a function that constructs a lambda function with a move-capture (C++1y only) and returns it.

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

using namespace std;

function<int ()> makeLambda(unique_ptr<int> ptr) {
    return [ ptr( move(ptr) ) ] () {
        return *ptr;
    };
}

int main() {
    // Works
    {
        unique_ptr<int> ptr( new int(10) );
        auto function1 = [ ptr(move(ptr)) ] {
            return *ptr;
        };
    }

    // Does not work
    {
        unique_ptr<int> ptr( new int(10) );
        auto function2 = makeLambda( std::move(ptr) );
    }

    return 0;
}

However, it seems as though upon returning, unique_ptr<int>'s copy constructor is called. Why is this/how can I get around this?

Link to paste: http://coliru.stacked-crooked.com/a/b21c358db10c3933

  • 1
    What happens if you change `auto function1 = ...` to `function function1 = ...`. I think the problem is with using `std::function`, not with using return types. – nosid Jun 23 '14 at 22:09
  • Doesn't seem to make a difference: http://coliru.stacked-crooked.com/a/00a26f08aef8944c –  Jun 23 '14 at 22:10
  • 1
    Well, it makes a difference. If I make the change, the first part no longer works. – nosid Jun 23 '14 at 22:13
  • Oh, sorry. I misunderstood your comment. –  Jun 23 '14 at 22:15
  • 1
    By the way, your code is very noisy. In modern C++, I would probably prefer to write it [like this](http://pastebin.com/ukHbXMqb). – Kerrek SB Jun 23 '14 at 22:19
  • @KerrekSB : Thanks. I do not usually write code like the above; just figured it would get more answers if it was easier to read. –  Jun 23 '14 at 22:23
  • @par: Hmm... I don't know if the extra text adds anything. You might argue that more people get bored and abandon the question if it's too long and too little of it pertains to the actual problem (which is your first function template). But it's your question :-) – Kerrek SB Jun 23 '14 at 22:24
  • The real question is why `std::function` isn't movable. Urgh. – Kerrek SB Jun 23 '14 at 22:25
  • @KerrekSB: Haha, that's true. Thanks. Minimize length, maximize legibility. Inversely proportional objectives? –  Jun 23 '14 at 22:26

1 Answers1

6

The problem is the std::function<int ()> return type, which is attempting to make a copy of the lambda. This will fail because the copy constructor is implicitly deleted due to the presence of the std::unique_ptr. Instead of storing the lambda in a std::function object, use return type deduction, now the lambda will be moved.

auto makeLambda(unique_ptr<int> ptr) {
    return [ ptr( move(ptr) ) ] () {
        return *ptr;
    };
}

Live demo

You should also probably change the argument type of makeLambda to unique_ptr<int>&&

Praetorian
  • 106,671
  • 19
  • 240
  • 328
  • Thanks. As for the &&, there is a pretty good argument for passing unique_ptr by value here: http://stackoverflow.com/questions/8114276/how-do-i-pass-a-unique-ptr-argument-to-a-constructor-or-a-function –  Jun 23 '14 at 22:21
  • @par Thanks for that link, I'd not seen that before. Nicol does make a good argument for passing by value. However, in case of a move-only type, which is being passed to a function that unconditionally moves the object, I think I still prefer the rvalue reference argument. IMHO, the error message is a little clearer if someone attempts to pass an lvalue to the function. – Praetorian Jun 23 '14 at 22:29