Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

std::function copying parameters?

My code:

#include <iostream>
#include <functional>
using namespace std;

struct A {
  A() = default;
  A(const A&) {
    cout << "copied A" << endl;
  }
};

void foo(A a) {}

int main(int argc, const char * argv[]) {
  std::function<void(A)> f = &foo;
  A a;
  f(a);
  return 0;
}

I'm seeing "copied A" twice on the console. Why is the object being copied twice, not once? How can I prevent this properly?

like image 450
lucas clemente Avatar asked Aug 10 '12 15:08

lucas clemente


People also ask

Can std :: function be copied?

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.

Does STD function copy?

Instances of std::function can store, copy, and invoke any CopyConstructible Callable target -- functions, lambda expressions, bind expressions, or other function objects, as well as pointers to member functions and pointers to data members.

What are copy constructors in C++?

The copy constructor is a constructor which creates an object by initializing it with an object of the same class, which has been created previously. The copy constructor is used to − Initialize one object from another of the same type. Copy an object to pass it as an argument to a function.

How does the copy function work C++?

The copy() function in C++ is used to copy the values from an array/vector within a specified range to another array/vector. This function is available in the <algorithm. h> header file.


1 Answers

The specialization std::function<R(Args...)> has a call operator with the following declaration:

R operator()(Args...) const;

In your case, this means that the operator takes A. As such, calling f(a) results in a copy due to the pass-by-value semantics. However, the underlying foo target also accepts its argument by value. Thus there will be a second copy when the parameter to f is forwarded to foo.

This is by design, and in fact if A had a move constructor there would be only one copy followed by a move construction -- and calling f(std::move(a)) would only result in two move constructions. If you feel that two copies are too much you need to reconsider whether both foo and f should take A instead of e.g. A const&, and/or whether A can have a sensible move constructor.

You can also do std::function<void(A const&)> f = &foo; without modifying foo. But you should reserve that for the case where modifying foo is beyond your control, and/or making A cheaply move constructible is not an option. There is nothing wrong with passing by value in C++11, so I suggest that either both should take A, or both should take A const&.

like image 105
Luc Danton Avatar answered Oct 03 '22 23:10

Luc Danton