为什么vector调用emplace会触发拷贝构造函数而set不会?
核心原因解释
你观测到的差异和emplace功能本身无关,是vector和set两类容器的底层存储结构差异导致的,相关技术点是序列式容器的动态扩容机制和关联式容器的存储特性:
- 首先明确
emplace系列函数的通用逻辑:所有容器的emplace操作都是直接在容器分配的目标内存上原地构造对象,本身不会触发新构造对象的拷贝操作,你看到的拷贝完全来自旧元素的迁移。 vector的拷贝构造触发原因:vector是连续内存存储的序列式容器,初始空容器插入第一个元素后,容量(capacity)仅为1(多数STL实现的默认策略)。当你调用emplace_back(15)插入第二个元素时,现有连续内存不够存储两个元素,容器会先申请更大的连续内存块,再把已经存储在旧内存里的第一个元素拷贝到新内存,再在新内存的末尾原地构造第二个元素。你观测到的拷贝就是旧元素迁移产生的,和新元素的emplace逻辑无关。set没有拷贝的原因:set是关联式容器,底层一般用红黑树实现,每个元素存储在独立的树节点中,插入新元素仅需要新增节点、调整树的指针结构,不需要移动已存在的旧元素,所以不会触发旧元素的拷贝操作。
验证方法
你可以在vector初始化后提前预留足够容量,就能消除扩容带来的拷贝:
vector<MyData> vx; vx.reserve(2); // 提前预留可存储2个元素的内存 auto it = vx.begin(); vx.insert(it,d1); cout<<"Calling emplace for vector"<<endl; vx.emplace_back(15);
修改后运行即可看到emplace_back阶段不会再触发拷贝构造,符合emplace原地构造的预期行为。
内容的提问来源于stack exchange,提问作者ankur katiyar
相关产品推荐
相关产品推荐

