C++17并行std::transform为何未将结果存入目标vector
你的代码存在两个问题,其中第一个是直接导致updated_bodies为空的核心原因,第二个是隐藏的逻辑bug。
1. 混淆了reserve()和resize()的作用
reserve()仅会预分配vector的底层内存容量,不会构造任何元素,也不会修改vector的元素计数(即size()的返回值)。你调用reserve(bodies.size())之后,updated_bodies实际依然是0个元素的空vector,此时拿到的updated_bodies.begin()指向未初始化的原始内存,并不是指向合法构造的SimulatedBody对象。std::transform的执行逻辑是对输出迭代器指向的已有对象做赋值操作,不会主动调用构造函数向vector插入新元素。你看到移动赋值运算符被打印,只是因为这块预分配的内存可访问,没有触发即时崩溃,本质是写入未初始化内存的未定义行为——vector完全不知道你往它的底层内存里写了内容,内部记录的元素个数始终是0,执行完自然表现为空vector。
并行执行策略确实要求输出迭代器必须是前向迭代器,不能用std::back_inserter(它属于输出迭代器,不满足并行要求),但你不需要用插入迭代器,只要提前把输出vector的大小调整到和输入一致即可,把reserve替换为resize就能解决迭代器合法性问题:
std::vector<SimulatedBody> updated_bodies; // 提前构造对应数量的默认SimulatedBody对象,保证迭代器指向合法可赋值的元素 updated_bodies.resize(bodies.size()); std::transform(std::execution::par_unseq, bodies.begin(), bodies.end(), updated_bodies.begin(), [&](const SimulatedBody &body) { return body.updated(*quadtree, m_dt); });
resize生成的默认对象会被transform写入的返回值直接覆盖,完全满足并行算法对前向输出迭代器的要求,没有额外性能损耗。
2. 自定义移动赋值运算符存在笔误
你写的调试版Body移动赋值运算符有一行明显的错误:
m_position = std::move(m_position);
这里你错误地移动了当前对象自身的m_position成员,而不是移动参数other的对应成员,正确写法应为:
m_position = std::move(other.m_position);
这个笔误会导致移动赋值后对象的位置数据处于有效但不确定的状态,哪怕你修复了vector大小的问题,后续模拟计算也会出现位置异常的bug。
注:你观察到移动赋值日志正常输出,不代表代码逻辑合法。对未初始化内存执行赋值操作是典型的未定义行为,可能在不同编译选项、不同平台下表现出完全不同的现象,包括不崩溃但数据异常、size计数不更新等。
内容的提问来源于stack exchange,提问作者steddy

