C++使用emplace_back和reserve向vector存对象仍出现非预期拷贝问题
问题原因
你对emplace_back的功能存在误解,加上类定义的规则限制,共同导致了多余拷贝的出现:
emplace_back使用方式错误emplace_back的核心作用是接收构造函数的参数,直接在vector分配的内存空间中原地构造对象,不需要提前创建对象实例。你传入已经构造完成的Vertex(1,2,3)临时对象时,已经额外完成了一次栈上对象创建,后续必须通过拷贝/移动操作把这个临时对象的数据写入vector的内存,完全没有用到emplace_back的原地构造能力,此时它的行为和push_back完全一致。- 自定义拷贝构造抑制了默认移动构造生成
C++标准规定,只要用户显式定义了拷贝构造函数,编译器就不会自动生成默认的移动构造函数。因此即便你用std::move把对象转为右值传入,也没有匹配的移动构造可以调用,最终还是会落到拷贝构造上,所以始终会打印COPIED!。
解决方案
完全消除拷贝的最优写法
直接把构造函数的参数传给emplace_back即可,不需要提前创建对象:
int main() { std::vector<Vertex> vert; vert.reserve(3); // 直接传构造参数,原地构造,无任何拷贝/移动 vert.emplace_back(1, 2, 3); vert.emplace_back(4, 5, 6); vert.emplace_back(7, 8, 9); return 0; }
这种写法会直接在vector预留的内存中调用Vertex的三参数构造函数,不会触发任何拷贝操作,运行后不会有COPIED!输出。
针对已有对象的场景
如果确实需要把已经创建好的对象存入vector,可以给Vertex类显式定义移动构造函数:
struct Vertex { size_t x, y, z; Vertex(size_t x, size_t y, size_t z) { this->x = x; this->y = y; this->z = z; } Vertex(const Vertex& v) : x(v.x), y(v.y), z(v.z) { std::cout << "COPIED!\n"; } // 新增移动构造函数 Vertex(Vertex&& v) noexcept : x(std::move(v.x)), y(std::move(v.y)), z(std::move(v.z)) { std::cout << "MOVED!\n"; } };
添加移动构造后,你再用vert.emplace_back(std::move(Vertex(1,2,3)))这类写法时,就只会调用开销极低的移动构造,不会触发拷贝。
另外补充:你多次对同一个左值对象调用std::move属于错误用法,对象第一次被移动后就处于合法但值不确定的状态,后续操作不符合C++规范。
内容的提问来源于stack exchange,提问作者Venci
相关产品推荐
相关产品推荐

