为何Guaranteed Copy Elision下push_back({arg1,arg2})与emplace_back(arg1,arg2)不等效?
为什么
push_back({arg1, arg2})没触发保证拷贝消除? 首先得明确保证拷贝消除(Guaranteed Copy Elision)的生效条件:它只在纯右值(prvalue)被用来直接初始化某个对象的时候才会触发——也就是说,编译器可以直接把prvalue的构造目标,指定为最终要初始化的那个内存位置,完全跳过临时对象的创建。
但push_back({arg1, arg2})的调用逻辑和这个场景不匹配:
push_back的右值重载版本是void push_back(T&&)。这里的{arg1, arg2}是用来初始化这个T&&参数的——也就是先构造一个临时的T对象(用{arg1, arg2}初始化),然后这个临时对象作为亡值(xvalue)被传递给push_back,最后push_back再把这个临时对象移动到vector的元素内存里。- 整个过程中,
{arg1, arg2}初始化的是push_back的参数(临时对象),而不是vector的元素。保证拷贝消除只能消除这个临时对象到参数的拷贝,但参数本身还是个临时,之后的移动是必须的(除非移动构造被额外优化,但那不属于保证拷贝消除的范畴)。
再看emplace_back(arg1, arg2)的核心区别:
emplace_back的设计就是直接在vector的内存空间里构造元素——它会把参数转发给T的构造函数,直接在vector新开辟的元素位置上调用T(arg1, arg2)完成构造,全程没有任何临时对象,自然也不需要移动操作。
你之前看到的回答里说的「prvalue直接初始化vector元素」,对应的场景应该是类似vector<T> v = {T{arg1, arg2}};这种情况——这里的T{arg1, arg2}是prvalue,直接用来初始化vector里的元素,这时候保证拷贝消除会生效,跳过临时对象。但push_back的调用逻辑是先构造临时对象作为参数,再移动,和这个场景完全不同。
总结一下:
push_back({...}):先构造临时对象(作为函数参数)→ 移动到vector元素emplace_back(...):直接在vector元素位置构造对象- 保证拷贝消除管的是「prvalue直接初始化最终对象」,管不到「prvalue先初始化函数参数临时对象,再移动」这个流程
内容的提问来源于stack exchange,提问作者Elliott
相关产品推荐
相关产品推荐

