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

std::vector::emplace()实现解析及自定义实现性能疑问

GCC std::vector::emplace() 源码执行逻辑解析

场景背景

自定义实现的vector类中,emplace()方法性能远低于std::vector::emplace(),查看GCC源码后无法理解其执行逻辑,以下是对这段源码的详细拆解。


GCC std::vector::emplace() 源码

template<typename _Tp, typename _Alloc>
template<typename... _Args>
typename vector<_Tp, _Alloc>::iterator
vector<_Tp, _Alloc>::
emplace(iterator __position, _Args&&... __args)
{
  const size_type __n = __position - begin();
  if (this->_M_impl._M_finish != this->_M_impl._M_end_of_storage
      && __position == end())
  {
    this->_M_impl.construct(this->_M_impl._M_finish,
                std::forward<_Args>(__args)...);
    ++this->_M_impl._M_finish;
  }
  else
    _M_insert_aux(__position, std::forward<_Args>(__args)...);
  return iterator(this->_M_impl._M_start + __n);
}

关键成员变量说明

先搞懂vector底层的几个核心指针:

  • _M_impl._M_start:指向底层动态数组的第一个元素
  • _M_impl._M_finish:指向当前已存元素的下一个位置(对应vector的size)
  • _M_impl._M_end_of_storage:指向底层数组的最后一个位置的下一位(对应vector的capacity)

代码逐行解析

  1. 记录插入位置偏移

    const size_type __n = __position - begin();
    

    计算插入位置相对于数组起始点的偏移量。后续如果发生扩容,原迭代器会失效,用这个偏移量可以生成新的有效迭代器。

  2. 快速路径判断

    if (this->_M_impl._M_finish != this->_M_impl._M_end_of_storage
        && __position == end())
    

    这是性能优化的核心分支,只有同时满足两个条件才会走这条最快的路径:

    • 容器还有剩余容量(_M_finish != _M_end_of_storage,即size < capacity)
    • 插入位置是容器末尾(__position == end())
  3. 快速路径执行

    • 原地构造元素:
      this->_M_impl.construct(this->_M_impl._M_finish, std::forward<_Args>(__args)...);
      
      调用分配器的construct方法,在_M_finish指向的空位置原地构造新元素。std::forward是完美转发,保证传入的参数左/右值属性不丢失,最大化构造效率。
    • 更新元素数量指针:
      ++this->_M_impl._M_finish;
      
      把_M_finish往后移一位,标记新元素已加入。
  4. 通用路径处理

    else _M_insert_aux(__position, std::forward<_Args>(__args)...);
    

    只要不满足快速路径的条件(比如在中间插入,或者容器已满需要扩容),就交给_M_insert_aux函数处理,它会完成:

    • 若容器已满,自动扩容(分配更大的新数组,批量移动/拷贝旧元素)
    • 将插入位置后的所有元素向后移动一位,腾出空间
    • 在目标位置原地构造新元素
    • 更新容器的size和指针
  5. 返回有效迭代器

    return iterator(this->_M_impl._M_start + __n);
    

    用之前记录的偏移量__n,从当前数组起始位置生成迭代器返回。避免了扩容后原迭代器失效的问题。


自定义vector emplace慢的可能原因

你的直觉(扩容时移动对象)没错,但GCC的实现做了末尾插入的快速路径优化:当插入到末尾且有剩余容量时,完全不需要移动任何元素,直接原地构造。如果你的自定义实现没有这个分支,每次插入都走扩容检查或元素移动,性能自然会差。另外_M_insert_aux里的扩容和元素移动也有批量优化(比如用移动语义代替拷贝),这些细节也会影响性能。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 16:05:38