小对象优化在使用 std::function 时毫无用处

wen*_*ndi 6 c++ c++11 std-function

许多主题告诉我们,使用像 lambda 表达式这样的小​​对象可以避免在使用std::function. 但我的研究表明并非如此。

这是我的实验代码,很简单

#include <iostream>
#include <functional>

using namespace std;

typedef std::function<int(int, int)> FUNC_PROTO;

class Test
{
public:
    int Add(int x, int y) { return x + y; }
};

int main()
{
    Test test;
    FUNC_PROTO functor = [&test](int a, int b) {return test.Add(a, b); };
    cout << functor(1, 2) << endl;
}
Run Code Online (Sandbox Code Playgroud)

我在centos7上编译它,gcc版本4.8.5 20150623但是valgrind显示了这一点:

==22903== HEAP SUMMARY:
==22903==     in use at exit: 0 bytes in 0 blocks
==22903==   total heap usage: 1 allocs, 1 frees, 8 bytes allocated
Run Code Online (Sandbox Code Playgroud)

即使我删除了引用捕获,也只是一个普通的 lambda 函数。它仍然花费 1 字节堆分配。

我进行小对象优化有什么问题吗?

更新:

感谢您的回复。我想我应该添加更多实验细节。

以排除可能导致参考捕获的原因。我删除了捕获,代码如下:

FUNC_PROTO functor = [](int a, int b) {return a + b; };
Run Code Online (Sandbox Code Playgroud)

Valgrind 展示了这一点:

==16691==   total heap usage: 1 allocs, 1 frees, 1 bytes allocated
Run Code Online (Sandbox Code Playgroud)

仍然是 1 字节堆分配。

我也尝试过这样做来消除 lambda 本身可能的影响(我认为不是)

FUNC_PROTO functor = [](int a, int b) {return a + b; };
FUNC_PROTO functor2 = [](int a, int b) {return a * b; };

FUNC_PROTO test = nullptr;
for ( int i = 0; i < 10; ++i)
{
    if (i % 2 == 0)
    {
        test = functor;
    }
    else
    {
        test = functor2;
    }
}
Run Code Online (Sandbox Code Playgroud)

Valgrind 显示:

==17414==   total heap usage: 12 allocs, 12 frees, 12 bytes allocated
Run Code Online (Sandbox Code Playgroud)

这可以证明函子不是完全基于堆栈的对象。

这是我的构建脚本:

g++ test.cpp -o test  -std=c++11 -g -O3 -DNDEBUG
Run Code Online (Sandbox Code Playgroud)

这是我的 valgrind 脚本:

valgrind --log-file=valgrind.log --tool=memcheck --leak-check=full --show-leak-kinds=all ./test
Run Code Online (Sandbox Code Playgroud)

Art*_*yer 5

旧版本的 libstdc++,例如 gcc 4.8.5 附带的版本,似乎只优化函数指针而不进行分配(如此处所示

由于该std::function实现没有您想要的小对象优化,因此您将不得不使用替代实现。要么升级你的编译器,要么使用boost::function,这与std::function.