5

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.

Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62
Daniel Lee
  • 205
  • 3
  • 7
  • 3
    duplicate of [What is the performance overhead of std::function?](https://stackoverflow.com/questions/5057382/what-is-the-performance-overhead-of-stdfunction) – underscore_d Dec 28 '17 at 12:31
  • 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). – Angew is no longer proud of SO Dec 29 '17 at 07:12

2 Answers2

9

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.

Angew is no longer proud of SO
  • 167,307
  • 17
  • 350
  • 455
1

The memory cost for std::function is true. As I tested on a RHEL 64bit machine, it is 32 bytes, while a lambda only takes 1 byte. But for runtime efficiency, the comments in the original cost cannot be reproduced.

With g++ -std=c++17 -O2, I got std::function much faster than lambda actually. With g++ -std=c++14 -O2, the results are close but lambda are still behind.

size of less1 as lambda: 1
size of less2 as function : 32
3722 time lambda sort: 47979086
6700 time function sort: 45291861
CS Pei
  • 10,869
  • 1
  • 27
  • 46