避免std::function的开销

我想对(自定义)单链表中的元素运行一组操作。遍历链表和运行操作的代码很简单,但是重复,如果到处复制/粘贴可能会出错。性能和谨慎的内存分配在我的程序中很重要,所以我想避免不必要的开销。

我想写一个包装器来包含重复的代码,并封装在链表的每个元素上发生的操作。由于操作中发生的函数不同,我需要捕获多个变量(在真实代码中),这些变量必须提供给操作,所以我考虑使用std::function。这个示例代码中的实际计算在这里是没有意义的。

#include <iostream>
#include <memory>

struct Foo
{
  explicit Foo(int num) : variable(num) {}
  int variable;
  std::unique_ptr<Foo> next;
};

void doStuff(Foo& foo, std::function<void(Foo&)> operation)
{
  Foo* fooPtr = &foo;
  do
  {
    operation(*fooPtr);
  } while (fooPtr->next && (fooPtr = fooPtr->next.get()));
}

int main(int argc, char** argv)
{
  int val = 7;
  Foo first(4);
  first.next = std::make_unique<Foo>(5);
  first.next->next = std::make_unique<Foo>(6);
#ifdef USE_FUNC
  for (long i = 0; i < 100000000; ++i)
  {
    doStuff(first, [&](Foo& foo){ foo.variable += val + i; /*Other, more complex functionality here */ });
  }
  doStuff(first, [&](Foo& foo){ std::cout << foo.variable << std::endl; /*Other, more complex and different functionality here */ });
#else
  for (long i = 0; i < 100000000; ++i)
  {
    Foo* fooPtr = &first;
    do
    {
      fooPtr->variable += val + i;
    } while (fooPtr->next && (fooPtr = fooPtr->next.get()));
  }
  Foo* fooPtr = &first;
  do
  {
    std::cout << fooPtr->variable << std::endl;
  } while (fooPtr->next && (fooPtr = fooPtr->next.get()));
#endif
}

如果以下列身份运行:

g++ test.cpp -O3 -Wall -o mytest && time ./mytest
1587459716
1587459717
1587459718

real    0m0.252s
user    0m0.250s
sys 0m0.001s

而如果以以下身份运行:

g++ test.cpp -O3 -Wall -DUSE_FUNC -o mytest && time ./mytest 
1587459716
1587459717
1587459718

real    0m0.834s
user    0m0.831s
sys 0m0.001s

这些计时在多次运行时相当一致,并且在使用std::function时显示出4倍的倍数。有没有更好的方法让我做我想做的事?

转载请注明出处:http://www.fymidi.com/article/20230526/1643662.html