现代编译器如何在c++;? 正如我从《有效C++》中所知道的,如果通过C++的值,而不是函数引用或函数指针,它将有更好的性能。那么,现代编译器如何优化这种场景呢

现代编译器如何在c++;? 正如我从《有效C++》中所知道的,如果通过C++的值,而不是函数引用或函数指针,它将有更好的性能。那么,现代编译器如何优化这种场景呢,c++,c++11,C++,C++11,或者我们通常不建议通过值传递自定义类的对象,但函数对象实际上与普通对象相同,只是在类中实现了“操作符()”。所以,在通过值传递这两个对象时,编译器处理这两个对象的方式肯定有所不同,对吗 下面是一个比较函数对象和函数指针的例子 #include <algorithm> #include <vector> #include <ctime> #include <iostream> bool cmp(int a, int b) { return a &l

或者我们通常不建议通过值传递自定义类的对象,但函数对象实际上与普通对象相同,只是在类中实现了“操作符()”。所以,在通过值传递这两个对象时,编译器处理这两个对象的方式肯定有所不同,对吗

下面是一个比较函数对象和函数指针的例子

#include <algorithm>
#include <vector>
#include <ctime>
#include <iostream>

bool cmp(int a, int b) { return a < b; }

int main() {
    std::vector<int> v(10000000);
    for (size_t i = 0; i < 10000000; ++i)
        v.push_back(rand());
    std::vector<int> v2(v);
    std::sort(v.begin(), v.end(), std::less<int>()); // This way would be faster than below;
    std::sort(v2.begin(), v2.end(), cmp);
}
#包括
#包括
#包括
#包括
boolcmp(inta,intb){返回a
在函数指针的情况下,编译器可能传递函数指针并执行间接函数调用,而不是进行直接函数调用甚至内联

相反,函数对象的
operator()
可能是内联的,或者至少是直接调用的,因为它不被传递,只传递数据(通过值或引用)。对于没有数据的函数对象,不传递任何内容(这将编译为伪整数,甚至不传递任何内容)

尤其是对于
std::function
,在函数指针的情况下,实现端几乎没有办法避免双重间接函数调用

#include <algorithm>
#include <vector>
#include <ctime>
#include <iostream>

bool cmp(int a, int b) { return a < b; }

int main() {
    std::vector<int> v(10000000);
    for (size_t i = 0; i < 10000000; ++i)
        v.push_back(rand());
    std::vector<int> v2(v);
    std::sort(v.begin(), v.end(), std::less<int>()); // This way would be faster than below;
    std::sort(v2.begin(), v2.end(), cmp);
}
lambda是进行此优化的最简单方法。以下是一个字符差异的示例:

#include <algorithm>
#include <vector>
#include <ctime>
#include <iostream>

int main() {
    std::vector<int> v(10000000);
    for (size_t i = 0; i < 10000000; ++i)
        v.push_back(rand());
    std::vector<int> v2(v);
    std::sort(v.begin(), v.end(), [] (int a, int b) { return a < b; }); // This way would be faster than below;
    std::sort(v2.begin(), v2.end(), +[] (int a, int b) { return a < b; });
}

#包含并检查反汇编)

在gcc 7.5的情况下,
std::sort
在内部使用
\u gnu\u cxx::\u ops::\u Iter\u comp\u Iter
模板,其外观如下:

模板
结构集成电路
{
_比较M___comp;
显式_GLIBCXX14_CONSTEXPR
_Iter_comp_Iter(_comp_comp):_M_comp(_GLIBCXX_MOVE(_comp)){}
模板
_GLIBCXX14_CONSTEXPR bool
运算符()
{返回bool(_M_comp(*_it1,*_it2));}
}
在第一种情况下,
\u Compare
std::less
,在第二种情况下--
bool(*)(int,int)

在第一种情况下,gcc内联比较,而在第二种情况下,它生成类似于
callq*%r13
的内容来调用存储在_M_comp中的指针

更新:
在对注释进行深入研究之后,发现问题不在于_Compare类型——gcc 7.5也可以使用函数指针内联小型纯函数,即使没有
inline
修饰符——而是在
std::sort
的内部工作中存在递归。这将抛出编译器,并生成间接调用。好消息是gcc 8+似乎没有这个缺点。

如果您将cmp()声明为内联,该怎么办?i、 e.
inlineboolcmp(inta,intb){返回a
函数ptr和functor的性能是否相同(因为gcc内联线都是)?@SPD\u Compare仍然是bool(*)(int,int),gcc仍然生成
callq*%r13
。我认为,从它使用指针的那一刻起,它就否定了自己的选择。此外,没有常量修饰符,因此编译器必须考虑_M_comp更改的可能性。请参见我的示例:使用内联,gcc不会为函数ptr生成callq。@SPD这是因为您不将指针存储在成员变量中,而是立即使用它,所以编译器可以内联它。复制上面列表中的_Iter_comp_Iter并使用它,您将看到gcc将停止内联。@SPD-hm,实际上它仍然内联它。但对于std::sort,情况并非如此。谢谢你的投入,一些可以玩的东西。