Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
277 views
in Technique[技术] by (71.8m points)

c++ - Is there call overhead if std::bind is used in recursive way?

I'm writing a template function which involved usage of f = std::bind(std::bind(std::bind(...))).

but I'm not sure whether the c++ compiler is smart enough to unfold the calling chain.
What I mean is:

  1. when creating functor f, is there multiple std::bind() invoked at runtime?
  2. when calling f(), does it involves calling multiple operator() at different layers of bind_functor object.

As a simple example: Does f2() run slightly faster than f1()?

#include <functional>

int add(int a, int b) {
  return a + b;
}

int main() {
  using namespace std::placeholders;
  auto f1 = std::bind(std::bind(&add, 1, _1), 2);
  auto f2 = std::bind(&add, 1, 2);
  return 0;
}

Update: I did some experiment. It seems f2() does run faster than f1(). And if you use std::function, it is even slower. Here is the experimental code (ubuntu/gcc 7.5.0, with optimization enabled. Without optimization, f2 is the slowest.). On my computer, the output is:

f1: 16851813
f2: 17567904
f3: 30655284

Here is the code (updated according to the comment of Nate):

#include <chrono>
#include <iostream>
#include <functional>

int add(int a, int b, int c) {
  return a + b + c;
}

int main() {
  using namespace std::placeholders;
  auto f1 = std::bind(std::bind(&add, 1, _1, _2), 2, _1);
  auto f2 = std::bind(&add, 1, 2, _1);
  std::function<int(int)> f3 = std::bind(&add, 1, 2, _1);
  const int N = 10000000;
  volatile int x = 0;

  {
    auto begin = std::chrono::system_clock::now();
    for (int n = 0; n < N; n++) {
      x = f1(x);
    }   
    auto end = std::chrono::system_clock::now();
    auto d = end - begin;
    std::cout << "f1: " << d.count() << std::endl;
  }

  x = 0;
  {
    auto begin = std::chrono::system_clock::now();
    for (int n = 0; n < N; n++) {
      x = f2(x);
    }   
    auto end = std::chrono::system_clock::now();
    auto d = end - begin;
    std::cout << "f2: " << d.count() << std::endl;
  }

  x = 0;
  {
    auto begin = std::chrono::system_clock::now();
    for (int n = 0; n < N; n++) {
      x = f3(x);
    }   
    auto end = std::chrono::system_clock::now();
    auto d = end - begin;
    std::cout << "f3: " << d.count() << std::endl;
  }
  return 0;
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

Whereas std::function uses type-erasure and so should do code equivalent to virtual call for operator(), bind's result can know real types and use static calls (which are simpler to inline by compiler).

Nested bind would do extra static calls, but probably inlined so might give same code.

Quickbench Demo confirms that for your example:

Same timing for nested or not nested bind, but std::function slower.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

2.1m questions

2.1m answers

60 comments

57.0k users

...