按指定字符串列表遍历vector写入文件:哪种实现开销更低?
哪种实现方法的整体开销更低?
需要将一个临时std::vector<std::string>的元素,按照给定std::vector<std::string> extensions的顺序写入文件。给定代码如下:
std::vector<std::string> data { "jpg yuvj420p 1080x2400 1:1 9:20", "jpeg yuvj420p 1536x2048 72:72 3:4", "jpg yuvj444p 1920x1080 1:1 16:9", "png rgba 150x150 NA NA", // ... 最多还有35(或56?)个元素,均以extensions中的某字符串开头 }; std::vector<std::string> extensions { "png", "jpg", "jpeg", // ... 还有2到4个扩展 }; std::ofstream file ("data.txt");
现有两种实现方法:
1. 直接遍历法
for (auto& ext : extensions) { for (auto& it : data) if (it.starts_with(ext)) file << it << '\n'; }
2. 使用std::erase_if法
for (auto& ext : extensions) { std::erase_if( data, [&ext](std::string& it) { if (it.starts_with(ext)) { file << it << '\n'; return true; } else return false; } ); }
两种方法均可得到符合extensions顺序的文件内容。第二种方法试图避免后续外层循环中重复遍历已写入文件的data元素,但std::erase_if会带来额外开销:包括(data.size() - 已匹配元素数)次谓词调用、元素移动操作,以及extensions.size()次data.erase调用。请问哪种方法的整体开销更低?
结论:直接遍历法开销更低(针对当前场景)
具体分析:
直接遍历法的开销:
本质是extensions.size()×data.size()次starts_with调用,没有内存元素移动、删除等操作。虽然会重复遍历已写入的元素,但结合题目里的规模——data最多56个元素,extensions最多6个左右,总调用次数最多56×6=336次,这个量级的字符串前缀判断开销微乎其微,完全可以忽略。std::erase_if法的额外成本:
每次erase_if确实会减少后续遍历的元素数量,但代价是:- 每次匹配到元素后,需要将vector中后续的所有元素向前移动(即使是string的移动语义,也涉及指针、长度等成员的赋值,而非零成本);
erase操作本身需要调整vector的内部状态;- 逻辑上比直接遍历更复杂,维护成本更高。
对于只有几十元素的data,这些额外开销的总和,远大于直接遍历多做的几次
starts_with判断。
补充:
如果data的规模达到上万甚至更大,erase_if法减少遍历次数的收益才会超过元素移动的开销,但当前场景完全不需要考虑这种情况。直接遍历法不仅开销更低,代码也更直观易懂。
内容的提问来源于stack exchange,提问作者Erendil
相关产品推荐
相关产品推荐

