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

原地构造与完美转发:为何emplace_back需移动构造函数?

问题分析与解决

为什么编译失败?

有两个核心原因:

  1. emplace_back用法错误
    你调用v.emplace_back(nonmovable_t{1})时,并非让vector原地构造对象——而是先在外部构造了一个临时nonmovable_t实例,再把这个临时对象传给emplace_back。此时emplace_back会尝试用这个临时对象作为参数构造vector内存中的元素,这会触发对移动构造函数的调用(临时对象属于右值),但你的类已经显式删除了移动构造,因此编译器直接报错。

  2. 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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 12:52:36