Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Should I copy an std::function or can I always take a reference to it?

In my C++ application (using Visual Studio 2010), I need to store an std::function, like this:

class MyClass    {    public:       typedef std::function<int(int)> MyFunction;       MyClass (Myfunction &myFunction);    private:       MyFunction m_myFunction;    // Should I use this one?       MyFunction &m_myFunction;   // Or should I use this one?    }; 

As you can see, I added the function argument as a reference in the constructor.

But, what is the best way to store the function in my class?

  • Can I store the function as a reference since std::function is just a function-pointer and the 'executable code' of the function is guaranteed to stay in memory?
  • Do I have to make a copy in case a lambda is passed and the caller returns?

My gut feeling says that it's safe to store a reference (even a const-reference). I expect the compiler to generate code for the lambda at compile time, and keep this executable code in 'virtual' memory while the application is running. Therefore the executable code is never 'deleted' and I can safely store a reference to it. But is this really true?

like image 536
Patrick Avatar asked Jan 03 '12 11:01

Patrick


People also ask

Should std :: function be passed by reference or value?

If there is any possibility you are storing a copy of the std::function , pass by value. Otherwise, either way is roughly equivalent: the only downside to by-value is if you are taking the same bulky std::function and having one sub method after another use it. Barring that, a move will be as efficient as a const& .

Does a reference make a copy C++?

With reference semantics, assignment is a pointer-copy (i.e., a reference). Value (or “copy”) semantics mean assignment copies the value, not just the pointer. C++ gives you the choice: use the assignment operator to copy the value (copy/value semantics), or use a pointer-copy to copy a pointer (reference semantics).

What is the point of std :: function?

Class template std::function is a general-purpose polymorphic function wrapper. Instances of std::function can store, copy, and invoke any Callable target -- functions, lambda expressions, bind expressions, or other function objects, as well as pointers to member functions and pointers to data members.

Why do you need to use a reference in the argument to the copy constructor?

A copy constructor defines what copying means,So if we pass an object only (we will be passing the copy of that object) but to create the copy we will need a copy constructor, Hence it leads to infinite recursion. So, A copy constructor must have a reference as an argument.


2 Answers

Can I store the function as a reference since std::function is just a function-pointer and the 'executable code' of the function is guaranteed to stay in memory?

std::function is very much not just a function pointer. It's a wrapper around an arbitrary callable object, and manages the memory used to store that object. As with any other type, it's safe to store a reference only if you have some other way to guarantee that the referred object is still valid whenever that reference is used.

Unless you have a good reason for storing a reference, and a way to guarantee that it remains valid, store it by value.

Passing by const reference to the constructor is safe, and probably more efficient than passing a value. Passing by non-const reference is a bad idea, since it prevents you from passing a temporary, so the user can't directly pass a lambda, the result of bind, or any other callable object except std::function<int(int)> itself.

like image 163
Mike Seymour Avatar answered Sep 22 '22 11:09

Mike Seymour


If you pass the function in to the constructor by reference, and don't make a copy of it, you'll be out of luck when the function goes out of scope outside of this object, as the reference will no longer be valid. That much has been said in the previous answers already.

What I wanted to add was that, instead, you could pass the function by value, not reference, into the constructor. Why? well, you need a copy of it anyway, so if you pass by value the compiler can optimize away the need to make a copy when a temporary is passed in (such as a lambda expression written in-place).

Of course, however you do things, you potentially make another copy when you assign the passed in function to the variable, so use std::move to eliminate that copy. Example:

class MyClass { public:    typedef std::function<int(int)> MyFunction;     MyClass (Myfunction myFunction): m_myfunction(std::move(myFunction))        {}  private:    MyFunction m_myFunction; }; 

So, if they pass in an rvalue to the above, the compiler optimises away the first copy into the constructor, and std::move removes the second one :)

If your (only) constructor takes a const reference, you will need to make a copy of it in the function regardless of how it's passed in.

The alternative is to define two constructors, to deal with lvalues and rvalues separately:

class MyClass { public:    typedef std::function<int(int)> MyFunction;     //takes lvalue and copy constructs to local var:    MyClass (const Myfunction & myFunction): m_myfunction(myFunction)        {}    //takes rvalue and move constructs local var:    MyClass (MyFunction && myFunction): m_myFunction(std::move(myFunction))        {}  private:    MyFunction m_myFunction; }; 

Now, you handly rvalues differently and eliminate the need to copy in that case by explicitly handling it (rather than letting the compiler handle it for you). May be marginally more efficient than the first but is also more code.

The (probably seen a fair bit around here) relevant reference (and a very good read): http://cpp-next.com/archive/2009/08/want-speed-pass-by-value/

like image 24
jsdw Avatar answered Sep 22 '22 11:09

jsdw