5

What I understand as a typical use of std::function

#include <iostream>
#include <functional>

using namespace std;

class C {
public: 
    C() { cout << "CREATING" << endl; }
    C(const C&) { cout << "COPY C "<< endl; };
    C(C&&) { cout << "MOVE C " << endl; };
    ~C() { cout << "DELETING"<< endl; }
    C& operator =(const C&) {
        cout << "COPY A " << endl; return *this;
    };
    C& operator =(C&&) {
        cout << "MOVE A" << endl; return *this;
    };
    void operator ()() const { cout << "CALLING" << endl; }
};

int main(int argc, char *argv[]) {
    function<void()> f = C();
    f();
    return 0;
}

yields following output

CREATING
MOVE C
DELETING
CALLING
DELETING

Apparently, temporary object is created on stack and then moved into function object. If move constructor is not provided, it is copied instead.
Is there a standard way of setting the target without need for a temporary object?

BartoszKP
  • 34,786
  • 15
  • 102
  • 130
Smiles
  • 1,733
  • 2
  • 11
  • 13

2 Answers2

5

The way that function is constructed from any functor F f is stipulated by the standard in §20.9.11.2.1 as (assuming f is a non-null, emphasis mine):

*this targets a copy of f initialized with std::move(f)

So there is no way to in-place construct a function. That leaves you with a choice between incurring that move:

function<void()> f1 = C{};

Or passing in some wrapper around C that is cheaper to move/copy, either one in which you manage externally:

C manage_me;
function<void()> f2 = std::ref(manage_me);

... or an allocated one bound to operator():

function<void()> f3 = std::bind(&C::operator(), std::make_shared<C>());

That last one could cause some headaches if operator() happens to be overloaded, as you'd have to cast it to the right type, which is an issue that none of the previous versions have to deal with.

function<void()> f4 = std::bind(
                          static_cast<void(C::*)()>(&C::operator()),
                          std::make_shared<C>()
                          );
Barry
  • 286,269
  • 29
  • 621
  • 977
4

You can use std::bind but you do not really need to implement operator() for that:

int main(int argc, char *argv[]) {
    C c;
    function<void()> f = std::bind( &C::operator(), &c );
    f();
    return 0;
}

output:

CREATING
CALLING
DELETING

of course you need to properly maintain lifetime of object c in this case. To make std::function to own C instance and make it more in-place construction std::shared_ptr can be used:

int main(int argc, char *argv[]) {
    function<void()> f = std::bind( &C::operator(), std::make_shared<C>() );
    f();
    return 0;
}
Slava
  • 43,454
  • 1
  • 47
  • 90
  • 1
    If he's doing `C()`, then the scope of the object will be limited anyway. –  Jan 14 '15 at 22:21
  • Of course, this isn't utilizing in-place construction but rather no construction at all. But still worth mentioning and probably useful sometimes somehow. – 5gon12eder Jan 14 '15 at 22:21
  • 1
    Well, no construction inside the function object. ;-) – 5gon12eder Jan 14 '15 at 22:25
  • If I have to maintain the lifetime of the object anyway, why not then use `function f = std::ref(C)`? – Smiles Jan 14 '15 at 22:25
  • @5gon12eder good point, added example for in-place construction. – Slava Jan 14 '15 at 22:26
  • That last version is very interesting. (Honestly, I'm a little surprised that it works.) If we are worried about the cost of copying the functor, it is probably large so `std::function` would have allocated memory anyway, so, assuming the shared pointer is small enough to make `std::function` utilize its small object optimization, we can create the functor on the free store anyway at no additional cost. – 5gon12eder Jan 14 '15 at 22:32
  • @Cynic added example where you do not need to maintain lifetime of the object – Slava Jan 14 '15 at 22:33