原地构造与完美转发:为何emplace_back需移动构造函数?
问题分析与解决
为什么编译失败?
有两个核心原因:
emplace_back用法错误
你调用v.emplace_back(nonmovable_t{1})时,并非让vector原地构造对象——而是先在外部构造了一个临时nonmovable_t实例,再把这个临时对象传给emplace_back。此时emplace_back会尝试用这个临时对象作为参数构造vector内存中的元素,这会触发对移动构造函数的调用(临时对象属于右值),但你的类已经显式删除了移动构造,因此编译器直接报错。vector扩容机制的隐含要求
即便修正用法,vector在容量不足时会自动扩容:分配新内存块,再把旧内存的元素转移到新内存。这个转移过程要求元素支持移动或拷贝构造,但你的类两者都已删除。编译器会提前检查到这个潜在问题,所以哪怕第一次emplace_back不需要扩容,也会报错。
如何在vector中原地构造不可移动对象?
要解决问题,需要同时做到两点:
- 正确使用emplace_back:直接传递构造函数的参数,让
emplace_back在vector的内存空间里直接调用构造函数,无需提前构造临时对象。 - 提前预留足够容量:避免vector触发扩容操作,这样就不需要移动现有元素。
修正后的代码如下:
#include <iostream> #include <utility> #include <vector> class nonmovable_t { public: nonmovable_t(int) { std::cout << "ctor" << std::endl; }; nonmovable_t(const nonmovable_t&) = delete; nonmovable_t(nonmovable_t&&) = delete; nonmovable_t& operator=(const nonmovable_t&) = delete; }; int main() { std::vector<nonmovable_t> v; v.reserve(1); // 提前预留容量,避免扩容 v.emplace_back(1); // 直接传构造参数,原地构造 return 0; };
这段代码可以正常编译运行,输出ctor,全程不会调用拷贝或移动构造函数。
如果要在其他自定义类中对这类不可移动对象进行原地构造,只需确保:
- 自定义类提供原地构造的接口(比如类似
emplace_back的成员函数,用完美转发传递构造参数) - 后续操作不会涉及移动该对象(比如自定义类不需要重新分配内存、移动内部存储的对象等)
内容的提问来源于stack exchange,提问作者Xeenych Xeenych
相关产品推荐
相关产品推荐

