You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++11中emplace_back与预分配后移动的性能及代码质量对比咨询

在C++11中两种vector初始化实现的性能与代码质量对比

先把两个函数的代码贴出来,方便对照分析:

void f2(const std::vector<std::string>& users) { 
    std::vector<std::pair<std::string, int>> userOccurancies(users.size()); 
    auto userOcIt = userOccurancies.begin(); 
    for (const auto & user : users) { 
        userOcIt->first = std::move(user); 
        userOcIt->second = 0; 
        userOcIt++; 
    } 
} 

void f(const std::vector<std::string>& users) { 
    std::vector < std::pair<std::string, std::size_t>> userCount; 
    userCount.reserve(users.size()); 
    for (auto& user : users) { 
        userCount.emplace_back(user, 0); 
    } 
}

性能分析:为什么f更快?

首先要戳破一个容易被忽略的细节:f2里的std::move(user)根本没起到移动的作用。因为user是const std::string&类型,std::move(user)会生成一个const std::string&&,而std::string的移动构造函数只接受非const的右值引用(std::string&&),所以这里实际上触发的是std::string的拷贝构造,而非移动构造。

接下来对比两者的执行流程:

  • f2的冗余开销:

    1. 先构造一个大小为users.size()的vector,每个std::pair都是默认构造的:std::string默认构造为空字符串,int默认初始化为0。
    2. 循环中对每个pair的first进行拷贝赋值(移动无效),second重新赋值为0(这一步完全冗余,因为默认已经是0了)。
      这里多了两次额外操作:std::string的默认构造,以及后续的赋值操作,比直接构造要多不少开销。
  • f的高效流程:

    1. 先调用reserve(users.size())预分配足够内存,避免后续扩容的内存拷贝开销。
    2. 循环中用emplace_back(user, 0)直接在vector的内存中构造std::pair:用user拷贝构造std::string,同时初始化std::size_t为0。
      整个过程是直接构造目标对象,没有额外的默认构造和赋值步骤,步骤更少,开销更低。

为什么性能分析结果随调用顺序变化?

这是典型的缓存预热效应:第一次调用函数时,相关的内存页可能还不在CPU缓存中,需要从内存加载,速度较慢;第二次调用时,数据已经在缓存里了,访问速度会快很多。所以性能测试时,应该先进行几次“预热”调用,然后多次测试取平均值,才能得到更准确的结果。

代码质量分析:f更符合现代C++风格

  • 简洁性:f的代码更短,逻辑更直观,不需要手动维护迭代器,也不需要提前构造元素再修改。
  • 可读性:emplace_back的语义很明确——直接在容器内构造元素,读者一眼就能明白代码的意图;而f2需要手动操作迭代器、赋值成员,代码更啰嗦,容易出错(比如忘记递增迭代器,或者误写成员赋值)。
  • 安全性:f2里的冗余赋值(userOcIt->second = 0)是不必要的,而且试图移动const对象的操作容易误导读者,让别人以为是移动实际是拷贝;f的代码没有这类歧义。

总结

在C11中,f的实现既更快,代码质量也更优。它避免了不必要的对象构造和赋值,代码更简洁易读,符合现代C的最佳实践。

内容的提问来源于stack exchange,提问作者user3360601

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.07 17:32:29