通过引用传递比较器函数 (C++11)

2024-03-28

我正在尝试加快我的代码速度(下面是最小的、可重现的示例),并且我被告知通过引用传递对于我的比较器函数来说是一种更有效的方法。那是我第一次听说这个短语,所以我查了一下,找到了一些带有示例的网站,但我不明白何时以及如何使用它。在这种情况下我将如何使用它?

#include <array>
#include <iostream>
#include <algorithm>
#include <fstream>
#include <ctime>
#include <random>

using namespace std;

class arrMember {
public:
    int var;
    arrMember(int var) :
        var(var) {}
    arrMember() {};
};

array<int, 1000000> arraySource;

array<arrMember, 1000000> arrayObjects;

bool compare(arrMember(x), arrMember(y)) {
    return (x.var < y.var);
}

void arrayPrint() {
    ofstream output("arrayPrint.txt");
    for (int k = 0; k != arrayObjects.size(); k++) {
        output << arrayObjects[k].var << endl;
    }

    output.close();
}

void sort() {
    int j = 0;
    for (auto i = arraySource.begin(); i != arraySource.end(); i++, j++) {
        arrayObjects[j] = arrMember(arraySource[j]);
    }

    sort(arrayObjects.begin(), arrayObjects.end(), compare);
}

int main(){
    random_device rd{};
    mt19937 engine{ rd() };
    uniform_int_distribution<int> dist{ 0, 9999 };
    for (int x = 0; x < arraySource.size(); ++x){
        arraySource[x] = dist(engine);
    }

    cout << "Executing sort...\n";
    clock_t t1 = clock();
    sort();
    clock_t t2 = clock();
    double timeDiff = ((double)(t2 - t1)) / CLOCKS_PER_SEC;

    cout << "Sort finished. CPU time was " << timeDiff << " seconds.\n";

    arrayPrint();

    return 0;
}

谢谢您的帮助。


对于非常小的类型,通过引用传递没有帮助;复制构造一个由单个组成的类int与获取现有实例的地址的成本基本上相同,并且复制构造意味着比较器不需要取消引用指针来查找值,它已经在本地堆栈上。

对于具有昂贵复制构造的较大类型,您可以更改(原始代码减去不必要的括号):

bool compare(arrMember x, arrMember y) {
    return x.var < y.var;
}

to:

bool compare(const arrMember& x, const arrMember& y) {
    return x.var < y.var;
}

并获得有意义的加速,但是对于一个简单的int包装类,你什么也得不到。

What will发挥作用,无论规模大小class问题是用函子(或 lambda,函子的语法糖)替换原始函数。std::sort将模板专门化为type比较器的类型,函数本身不是类型;它们实际上是共享相同原型的一组函数的实例。因此,如果您同时实现:

bool compare(const arrMember& x, const arrMember& y) {
    return x.var < y.var;
}
bool compareReverse(const arrMember& x, const arrMember& y) {
    return x.var > y.var;
}

并打电话std::sortcompare and compareReverse在你的程序的不同点,它只进行一种专业化std::sort for bool (*)(const arrMember&, const arrMember&),并且该单一特化实际上必须通过指针传递并调用所提供的函数;调用函数的成本明显高于执行比较本身的微不足道的成本,并且通过指针调用通常更昂贵。

相比之下,函子(和 lambda)是独特的类型,因此std::sort可以完全专门化它们,包括内联比较,因此不会发生对比较器函数的调用;比较器逻辑直接内联到独特的专业化中std::sort。所以而不是:

bool compare(const arrMember& x, const arrMember& y) {
    return x.var < y.var;
}
std::sort(..., compare);

你可以这样做:

struct compare {
    bool operator()(const arrMember& x, const arrMember& y) const {
        return x.var < y.var;
    }
};
std::sort(..., compare());

或者将整个内容内联为 C++11 lambda:

std::sort(..., [](const arrMember& x, const arrMember& y) { return x.var < y.var; });

无论哪种方式,代码都会运行得更快;上帝螺栓表演 https://godbolt.org/z/E3BJkJ这两种函数指针方法几乎是相同的,而使用函子方法,相对于函数指针方法,您可以将运行时间减少大约三分之一(在这种情况下,可以节省更多的值传递,但几乎不值得考虑)大多数时候;我会默认路过const参考,并且只有在分析表明速度很慢并且类型足够简单以至于按值传递可能会有所帮助时才考虑切换)。

模板和函子的这种好处就是 C++ 的原因std::sort可靠地击败Cqsort当使用得当时; C 缺乏模板,因此无法专门化qsort无论如何,并且必须始终通过函数指针调用比较器。如果你使用std::sort有了函数,并没有真正的改进qsort,但与函子/lambda 一起使用,它会生成much更快的代码以生成为代价more代码(独特的专业化std::sort对于每个函子/lambda)。通过复制粘贴实现的代码,您可以在 C 中获得相同的好处qsort,摆脱比较器并自己内联比较,但这是一个lot维护费用; C++ 模板为您完成 99% 的工作,您只需要记住对回调使用函子/lambda,而不是原始函数。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

通过引用传递比较器函数 (C++11) 的相关文章

随机推荐

  • 使用 Karma / Jasmine 进行 Angular 8 测试 -> 角度路由中的 loadChildren 未覆盖 100% 代码覆盖率

    从 Angular 7 升级到 Angular 8 后 应用程序路由的 loadChildren 发生了重大变化 当这些问题得到修复并且所有测试都在运行时 我不再获得 100 的代码覆盖率 因为 loadChildren 不再是 字符串 而
  • 直接调用 vs 调用 vs 启动

    我在使用 Tivoli Workload Scheduler 运行批处理文件时遇到此问题 有一个第三方程序 假设它的名称是program exe 该批处理文件包含以下命令来调用program exe program exe param1 p
  • 多个力布局图,其中 d3 位于单独的 svg/div 中

    我在使用 d3 创建多个力布局图并从 json 文件读取数据时遇到问题 我使用 for 循环来迭代图表 为每个图表创建一个单独的 div 其中包含一个 svg 问题是 力布局仅应用于最后创建的布局 因此基本上其他布局仅在左上角显示一个点 我
  • UICollectionView 上的 register(_:forCellWithReuseIdentifier:) 有什么问题?

    我正在与一个UICollectionView As dequeueReusableCell withReuseIdentifier for 期望您必须使用以下方法注册类或 nib 文件register forCellWithReuseIde
  • 以极高的速度获取行

    我在 Oracle 中有一个非常大的表 数亿行 包含数字和字符串 我需要读取该表的所有内容 对其进行格式化并写入文件或任何其他资源 一般来说 我的解决方案如下所示 package my odp import java io Buffered
  • 传递零大小的数组,保存分配?

    在此代码示例中 第 114 页基础扎实的 Java 开发人员 https rads stackoverflow com amzn click com 1617290068 最后一行 Update updates lu toArray new
  • 当子组件发生变化时,父组件是否会重新渲染?

    我有一个父组件 如下所示 const Parent gt return
  • Code Golf:数字的质因数[关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 Locked 这个问题及其答案是locked help locked posts因为这个问题是题外话 但却具有历史意义 目前不接受新的答案
  • CruiseControl.Net 仪表板 + Apache

    我正在尝试让 cc net 仪表板在也有 apache 的构建机器上运行 我尝试按照描述安装 mod aspdotnethere http weblogs asp net israelio archive 2005 09 11 424852
  • 辅助服务无法读取所有屏幕内容

    Issue 没有在 Android 馅饼中获取屏幕上的所有文本 检查直到牛轧糖代码工作正常 Device 小米 MiA1 Android One 版本 9 0 XML 设置
  • 禁用右键单击表单字段级别

    我需要通用功能 可以禁用右键单击表单字段 document oncontextmenu function e var el window event srcElement e target var tp el tagName if tp t
  • 在 test_package 中使用过滤器参数来跳过测试

    我想在期间运行我的包单元测试R CMD check 但跳过需要互联网连接的测试 按照惯例 所有需要互联网的单元测试都有这个词network在他们的文件名中 因此我的run all R包含 library testthat test pack
  • 未知自定义结构上的结构化绑定

    简洁版本 我希望能够将结构转换为元组 至少是类型 在下面的代码中 转换为元组函数不起作用 因为可变参数不能在结构化绑定中使用 据我所知 关键行是 自动 值 值 struct Vec3 float x float y float z temp
  • PySpark:添加一个新列,其中包含从列创建的元组

    这里我创建了一个数据框 如下所示 df spark createDataFrame a 5 R X b 7 G S c 8 G S Id V1 V2 V3 看起来像 Id V1 V2 V3 a 5 R X b 7 G S c 8 G S 我
  • 追加克隆或动态创建 DOM - 哪个更好?

    我希望从 ajax 调用返回的数组中生成以下列表 ul li li ul
  • Asciidoc 中文字内的替换

    似乎没有办法在 Asciidoc 的文字文本中解析变量 属性 替换 否则我会遗漏一些东西 我希望能够设置一个变量 然后在代码块或文字字符串中调用它 如下所示 version 1 0 1 code tar xzvf mysoftware ve
  • the_title 函数返回字符串而不是 WordPress 中的 echo

    在Wordpress中 如何更改the title 回显标题以返回字符串的函数 title反而 我正在尝试 the title gt title the title title 两种方式 Use get the title https de
  • 通过 Tweepy 去除推文中的换行符

    我正在寻找从 Twitter API 提取数据并创建一个管道分隔的文件 我可以对其进行进一步处理 我的代码目前如下所示 auth tweepy OAuthHandler CONSUMER KEY CONSUMER SECRET auth s
  • PHP mkdir 问题!

    我尝试创建一些像这样的目录 mkdir photos cat sku 0777 true 它使用 0777 权限创建第一个目录 但在创建第二个目录时使用 000 作为其权限 因此无法创建第三个目录 请问有解决方法吗 谢谢 理查德 这解决了这
  • 通过引用传递比较器函数 (C++11)

    我正在尝试加快我的代码速度 下面是最小的 可重现的示例 并且我被告知通过引用传递对于我的比较器函数来说是一种更有效的方法 那是我第一次听说这个短语 所以我查了一下 找到了一些带有示例的网站 但我不明白何时以及如何使用它 在这种情况下我将如何