Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Constructing std::function target in-place

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?

like image 824
Smiles Avatar asked Jan 14 '15 22:01

Smiles


1 Answers

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>()
                          );
like image 132
Barry Avatar answered Sep 22 '22 10:09

Barry