两个std::map打印实现的性能差异对比及最优方案咨询
两个C++实现的性能与优化对比
问题背景
以下两个C++代码实现功能相近,现分析二者在优化、运行速度上的差异,并说明哪种方案更优及原因:
第一个示例代码
std::map<std::vector<int>, std::vector<double>> data; printMap(&data); ... void printMap(std::map<std::vector<int>, std::vector<double>> *p_data){ for(std::map<std::vector<int>, std::vector<double>>::iterator itr = p_data->begin(); itr != p_data->end(); ++itr){ for(auto it = itr->first.begin(); it != itr->first.end(); ++it){ std::cout << *it << std::endl; } for(auto it2 = itr->second.begin(); it2 != itr->second.end(); ++it2){ std::cout << *it2 << std::endl; } } }
第二个示例代码
std::map<std::vector<int>, std::vector<double>> data; printMapRef(data); void printMapRef(std::map<std::vector<int>,std::vector<double>> &data){ for(std::map<std::vector<int>, std::vector<double>>::iterator itr = data.begin(); itr != data.end(); ++itr){ std::vector<int> tempVecInt = (*itr).first; std::vector<double> tempVecDouble = (*itr).second; for (int i = 0; i < tempVecInt.size(); i++){ std::cout << tempVecInt.at(i) << " "; } for (int j = 0; j < tempVecDouble.size(); j++){ std::cout << tempVecDouble.at(j) << " "; } } }
核心差异与性能分析
不必要的容器拷贝(最影响性能的点)
第二个示例中,std::vector<int> tempVecInt = (*itr).first;和std::vector<double> tempVecDouble = (*itr).second;会触发vector的深拷贝:复制原vector的所有元素到临时对象中。这会带来额外的内存分配、数据拷贝开销,当vector元素数量大时,会显著拖慢程序运行速度。而第一个示例直接遍历原map中存储的vector元素,无任何拷贝操作。迭代方式与边界检查
第二个示例用at()访问vector元素,at()会强制做下标越界检查,虽然提升了安全性,但会带来微小的性能损耗;第一个示例用迭代器遍历,无额外边界检查,效率更高。参数传递方式
第一个用指针传递,第二个用引用传递:二者性能几乎无差异(都是传递地址),但引用更安全——无需担心空指针崩溃(第一个函数未做空指针判断,若传入nullptr会直接崩溃),且代码可读性更好。IO操作效率
第一个示例用std::endl输出,每次都会刷新输出缓冲区;第二个用空格分隔输出,无频繁刷新操作。IO操作本身是程序的性能瓶颈之一,频繁刷新会大幅降低运行速度,这是第一个示例的明显缺陷。
最优方案及优化建议
第一个示例的核心逻辑(无拷贝遍历)更优,但可做以下优化:
- 将参数从指针改为const引用(因为函数仅读取数据,无需修改):
void printMap(const std::map<std::vector<int>, std::vector<double>> &data),既避免空指针风险,又符合const正确性。 - 把
std::endl替换为'\n',减少不必要的缓冲区刷新,提升IO效率。 - 用
auto简化迭代器声明(C++11及以后支持):auto itr = data.begin(),代码更简洁。
第二个示例的深拷贝问题是致命性能缺陷,不建议使用,除非有特殊需求必须复制容器。
内容的提问来源于stack exchange,提问作者AntonU
相关产品推荐
相关产品推荐

