I heard that cost of std::function
is heavier than auto
to deal with a lambda function. effective modern c++ item5. What I want is to clarify the mechanism why std::function
use more memory than auto
with some sample code.
Could somebody help me?
edit
class Widget {
public:
Widget(int i) : i_(i) {}
bool operator<(const Widget& o) { return o.value() > i_; }
int value() const { return i_; };
private:
int i_;
int dummy_[1024];
};
int main() {
// performance difference between auto and std::function
{
auto less1 = [](const auto& p1, const auto& p2) {
return *p1 < *p2;
};
std::cout << "size of less1: " << sizeof(less1) << endl;
function<bool(const std::unique_ptr<Widget>&,
const std::unique_ptr<Widget>&)>
less2 = [](const std::unique_ptr<Widget>& p1,
const std::unique_ptr<Widget>& p2) {
return *p1 < *p2;
};
std::cout << "size of less2: " << sizeof(less2) << endl;
{
// auto
std::vector<std::unique_ptr<Widget>> ws1;
for (auto i = 0; i < 1024*100; ++i) {
ws1.emplace_back(new Widget(std::rand()));
}
auto start = std::chrono::high_resolution_clock::now();
std::sort(ws1.begin(), ws1.end(), less1);
auto end = std::chrono::high_resolution_clock::now();
cout << ws1[0].get()->value() << " time: " << (end - start).count() << endl;
}
{
// std::function
// 25% slower than using auto
std::vector<std::unique_ptr<Widget>> ws2;
for (auto i = 0; i < 1024*100; ++i) {
ws2.emplace_back(new Widget(std::rand()));
}
auto start = std::chrono::high_resolution_clock::now();
std::sort(ws2.begin(), ws2.end(), less2);
auto end = std::chrono::high_resolution_clock::now();
cout << ws2[0].get()->value() << " time: " << (end - start).count() << endl;
}
}
return 0;
}
it's from https://github.com/danielhongwoo/mec/blob/master/item5/item5.cpp
I think this code shows me using std::function
is slower than using auto. But not usage of memory. I just want to prove it with some real code.
Note that when talking about overhead of std::function (i.e. that std::function is "heavy"), usually the performance overhead is meant. Its memory overhead will be minor (around 2 extra pointers, I'd guess).
sorting - Why is a C++ Lambda function much faster as compare function than an equivalent object - Stack Overflow. Stack Overflow for Teams – Start collaborating and sharing organizational knowledge.
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.
The Functor is self-documenting by default; but Lambda's need to be stored in variables (to be self-documenting) inside more-complex algorithm definitions.
There are two performance implications of using std::function that might surprise you: When calling a std::function, it does a virtual function call. When assigning a lambda with significant captures to a std::function, it will do a dynamic memory allocation!
Because they are objects rather than pointers they can be inlined very easily by the compiler, much like functors. This means that calling a lambda many times (such as with std::sort or std::copy_if) is much better than using a global function. This is one example of where C++ is actually faster than C.
To make func accepts both lambda and lambda2 , std::function needs to have constructors that take any function object or plain function that satisfies its signature. And we need to perform type erasure to achieve this behavior. There are various techniques to implement type erasure in C++, and it is not a topic I can fit into this post.
This means that calling a lambda many times (such as with std::sort or std::copy_if) is much better than using a global function. This is one example of where C++ is actually faster than C. std::function is a templated object that is used to store and call any callable type, such as functions, objects, lambdas and the result of std::bind.
std::function
can store an arbitrary callable. In therefore has to engage in type erasure to be able to store something of an arbitrary type. This can require dynamic allocation in the general case, and it definitely requires an indirect call (either a virtual call or a call through a function pointer) on each invocation of operator ()
.
The type of a lambda expression is not std::function
, it's an unnamed class type with operator()
defined (the lambda's closure type). Using auto a
to store a lambda makes the type of a
this precise closure type, which has no overhead.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With