我应该复制一个 std: : 函数,还是可以总是引用它?

在我的 C + + 应用程序中(使用 Visual Studio 2010) ,我需要存储一个 std: : 函数,如下所示:

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?
};

如您所见,我在构造函数中添加了函数参数作为引用。

但是,在我的类中存储函数的最佳方法是什么呢?

  • 由于 std: : function 只是一个函数指针,并且函数的“可执行代码”保证会保留在内存中,我是否可以将函数存储为引用?
  • 我是否必须复制一个副本,以防传递一个 lambda 并且调用者返回?

我的直觉告诉我,存储引用(甚至是常量引用)是安全的。我希望编译器在编译时为 lambda 生成代码,并在应用程序运行时将这些可执行代码保存在“虚拟”内存中。因此,可执行代码永远不会被“删除”,我可以安全地存储对它的引用。但这是真的吗?

54416 次浏览

Copy as much as you like. It is copyable. Most algorithms in standard library require that functors are.

However, passing by reference will probably be faster in non-trivial cases, so I'd suggest passing by constant reference and storing by value so you don't have to care about lifecycle management. So:

class MyClass
{
public:
typedef std::function<int(int)> MyFunction;
MyClass (const Myfunction &myFunction);
// ^^^^^ pass by CONSTANT reference.
private:
MyFunction m_myFunction;    // Always store by value
};

By passing by constant or rvalue reference you promise the caller that you will not modify the function while you can still call it. This prevents you from modifying the function by mistake and doing it intentionally should usually be avoided, because it's less readable than using return value.

Edit: I originally said "CONSTANT or rvalue" above, but Dave's comment made me look it up and indeed rvalue reference does not accept lvalues.

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.

I would suggest you to make a copy:

MyFunction m_myFunction; //prefferd and safe!

It is safe because if the original object goes out of scope destructing itself, the copy will still exist in the class instance.

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/

As a general rule (especially if you're using these for some highly threaded system), pass by value. There is really no way to verify from within a thread that the underlying object is still around with a reference type, so you open yourself up to very nasty race and deadlock bugs.

Another consideration is any hidden state variables in the std::function, for whom modification is very unlikely to be thread-safe. This means that even if the underlying function call is thread-safe, the std::function wrapper's "()" call around it MAY NOT BE. You can recover the desired behavior by always using thread-local copies of the std::function because they'll each have an isolated copy of the state variables.