代码之家  ›  专栏  ›  技术社区  ›  Xiaoyong Guo

如果以递归方式使用std::bind,是否存在调用开销?

  •  0
  • Xiaoyong Guo  · 技术社区  · 5 年前

    我正在编写一个模板函数,其中包括 f = std::bind(std::bind(std::bind(...))) .

    但是我不确定C++编译器是否足够聪明来打开调用链。
    我的意思是:

    1. 创建函子时 f ,有多个吗 std::bind() 在运行时调用?
    2. 打电话的时候 f() ,是否需要打电话 倍数 operator() 在bind_函子对象的不同层。

    举个简单的例子:是吗 f2() 跑得略快于 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;
    }
    

    更新: 我做了一些实验。看来 f2() 你跑得比我快吗 f1() .如果你使用 std::function ,甚至更慢。以下是实验代码(ubuntu/gcc 7.5.0,启用了优化功能。没有优化, f2 是最慢的。)。在我的电脑上,输出是:

    f1: 16851813
    f2: 17567904
    f3: 30655284
    

    以下是代码(根据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;
    }
    
    0 回复  |  直到 5 年前
        1
  •  0
  •   Jarod42    5 年前

    鉴于 std::function 使用类型擦除,因此应该执行相当于虚拟调用的代码 operator() , bind 的结果可以知道实际类型并使用静态调用(编译器内联更简单)。

    嵌套的 绑定 将执行额外的静态调用,但可能是内联的,因此可能会给出相同的代码。

    Quickbench Demo 确认您的示例:

    嵌套或不嵌套的时间相同 绑定 但是 std::函数 更慢的。