【问题标题】:How to efficiently change member data of all objects in a vector?如何有效地更改向量中所有对象的成员数据?
【发布时间】:2018-12-03 14:05:31
【问题描述】:

给定 vector 指向类对象的指针,在现代 C++ 中更改对象成员数据的“首选”(最有效/性能/简洁)方法是什么?当然,我可以使用for 循环来迭代vector,但是将for_each 与lambda 表达式一起使用会是更好的选择吗?还有其他更好的方法吗?

例如,假设我们有 vector<Person*> successfulPeoplePerson 类,其中包含两个成员变量 bool isHappyisRich 需要将所有 @987654331 从 false 更改为 true @successfulPeople 中的对象。

【问题讨论】:

  • 为什么你认为任何东西都会比 for 循环更高效?
  • ranged-for 是“最好的”,因为它最容易维护
  • 嗯,部分展开的循环、SIMD 或并行(线程)循环都可以比简单循环更有效。但是 C++ 优化器非常擅长转换代码(它们可以自动执行展开和 SIMD,以及只需一点点 #pragma omp parallel 的并行循环),如果你不得不问这个问题,编译器几乎肯定比它更擅长优化它你会的。
  • @PhysicsCodingEnthusiast:没有什么可以改进的。您问题的基础是过早的优化。以正确且相当直接/惯用的方式编写代码;如果它被证明太慢,那么找出它太慢的地方然后处理它。事实上,我对你的代码最关心的不是那种循环。事实上,您正在循环访问该数据的 指针 数组,这很可能会破坏缓存的一致性。如果这是性能关键代码,那么第 1 步是直接使用 vector<Person>
  • @NicolBolas 我已经有了一个完整的、可以工作的代码,并且对一些方面有疑问,并且想在我认为我可以改进的领域进行磨练——因此,这个问题。同样,一个原因是因为我习惯于在Mathematica 代码中不鼓励使用for 循环,所以我对此感到好奇。我觉得问什么被认为是“简单”/“显而易见”的问题真的会扼杀好奇心和羞耻,这真的很不幸。指针向量的原因是因为我有一个唯一指针的主向量,这是一个包含对象子集的向量。

标签: c++ performance vector c++17


【解决方案1】:

从技术上讲,for_each 更可取,因为它允许指定其执行策略:

#include <algorithm>
#include <vector>
#include <execution>

int main() {
    std::vector<int> v{0, 1, 2};
    std::for_each(std::par_unseq, v.begin(), v.end(), [](int &x){ x += 40; });
}

实际上,如果你尝试编译上面的代码,当前的编译器会拒绝:

$ clang -v -std=c++17 meow.cpp |& gawk '/execution/ { on = 1 } on || NR == 1 { print }' | sed 's/^/    /'
clang version 6.0.0 (tags/RELEASE_600/final)
meow.cpp:5:10: fatal error: 'execution' file not found
#include <execution>
         ^~~~~~~~~~~
1 error generated.

$ g++ -v meow.cpp |& tail -9 | sed 's/^/    /'
GNU C++17 (GCC) version 8.1.1 20180531 (x86_64-pc-linux-gnu)
    compiled by GNU C version 8.1.1 20180531, GMP version 6.1.2, MPFR version 4.0.1, MPC version 1.1.0, isl version isl-0.19-GMP

GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
Compiler executable checksum: c1584951f18917e503c3b4657c1f0dc5
meow.cpp:5:10: fatal error: execution: No such file or directory
 #include <execution>
          ^~~~~~~~~~~
compilation terminated.

因为 Parallelism TS 可能尚未在当前优先级列表中(尽管许多 C++20 功能都在。)

至于for 循环,there is no standard attribute that specifies parallel/otherwise non-sequential loop execution,但clang,例如provides pragmas to optimize loops

因此,尽管当前标准表明 for_each 可以(可能)表现更好,但当前现实的选择实际上是 for-loop 和 pragmas。 :-\

【讨论】:

  • 感谢您的回复!绝对是我以前从未遇到过的答案中的一些有趣的新内容。将不得不阅读更多关于for_each 的执行政策。
  • 好吧,正如我所说,我还没有看到它在任何地方实现,所以你的阅读将是一项长期投资。 :-\
【解决方案2】:

没有。 for 循环和 for each 只是做同样的事情,但语法不同。如果您只是在容器中搜索一个元素,其他数据结构(如二叉树)可能更有效,但无论哪个容器,只要您需要遍历整个数据结构,复杂度将是 O(n )。当然,即使复杂度相同,取决​​于数据结构的存储方式(即在连续内存中),速度也会有所不同。

【讨论】:

  • 当两个算法具有相同的复杂度顺序(例如,在这种情况下为 O(n)),那么前置因素就变得很重要:减少特定的操作/计算永远不会是一件坏事2 或 4 倍 :-)
  • @AnInquiringMind 是的,这是真的。但是,如果您只是像您的示例一样进行简单的布尔状态更新,除非您对程序进行多线程处理,否则您将无法获得更快的速度,除非这是您正在寻找的答案。即使对于一些复杂的算术计算,即使使用 SIMD 也可能不会更快,因为 SIMD 严重依赖并行计算来减少时间,所以如果您的计算不是独立的,那么没有太大帮助。
猜你喜欢
  • 1970-01-01
  • 2016-08-31
  • 2021-05-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-04
相关资源
最近更新 更多