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

std::vector::resize调用已删除拷贝构造函数问题咨询及求解

哈哈,这个坑我当初踩过!让我一步步给你捋清楚~

问题1:为何已有默认构造的情况下,std::vector::resize仍尝试调用已删除的拷贝构造函数?

你可能忽略了std::vector::resize的一个关键场景:当新的大小超过当前vector的容量(capacity)时,vector需要重新分配内存,这时候要把原有的元素转移到新的内存空间里。

你给Mesh类加了移动赋值运算符,根据C规则,这会隐式删除拷贝构造和拷贝赋值,但更关键的是:如果你只声明了移动赋值,编译器不会自动生成默认的移动构造函数(C标准规定,只有当类没有用户声明的任何拷贝/移动构造、赋值运算符或析构函数时,才会自动生成移动构造)。

这就导致了:当vector需要扩容转移元素时,因为没有移动构造函数可用,编译器会退而求其次尝试调用拷贝构造——但你的拷贝构造已经被删除了,所以编译报错。哪怕Mesh有默认构造,扩容时的元素转移步骤才是触发报错的原因。

问题2:是否因未满足std::vector::resize的某项要求导致失败?

完全是!std::vector::resize的要求不止是value_type可默认构造,它的行为分两种情况:

  • 如果新大小n <= 当前容量:只需要元素是DefaultInsertable(也就是有默认构造),这时候不会触发拷贝/移动;
  • 如果新大小n > 当前容量:需要先扩容,然后把原元素转移到新内存,再构造新元素。这时候要求元素是MoveInsertable(支持移动构造)或者CopyInsertable(支持拷贝构造)——你的Mesh类两者都不满足,所以直接失败。

问题3:如何在保留移动赋值运算符的前提下解决该问题?

有三个靠谱的方案,你可以根据需求选:

方案1:显式默认移动构造函数

既然你要保留移动赋值,不如顺便给Mesh加上默认的移动构造,让编译器帮你生成符合要求的移动语义:

class Mesh {
public:
    Mesh() = default; // 你的默认构造
    Mesh(Mesh&&) = default; // 显式要求编译器生成默认移动构造
    Mesh& operator=(Mesh&&) = default; // 保留你的移动赋值

    // 其他成员代码...
};

这样vector扩容时会用移动构造转移元素,完全避开拷贝构造,完美解决问题。

方案2:提前预留足够容量

如果你确定要resize到10个元素,可以先调用reserve提前分配足够的内存,这样resize时就不需要扩容,也就不会触发元素转移:

Model myModel;
myModel.meshes.reserve(10); // 提前把容量拉到10
myModel.meshes.resize(10); // 现在只需要默认构造新元素,不会碰拷贝/移动构造

这个方案适合你明确知道最终大小的场景,不需要修改Mesh类的定义。

方案3:恢复拷贝构造(如果允许的话)

如果Mesh类本身是可以被拷贝的,你可以显式默认拷贝构造和拷贝赋值,这样既保留移动赋值,又恢复拷贝能力:

class Mesh {
public:
    Mesh() = default;
    Mesh(const Mesh&) = default; // 恢复拷贝构造
    Mesh& operator=(const Mesh&) = default; // 恢复拷贝赋值
    Mesh& operator=(Mesh&&) = default; // 保留移动赋值

    // 其他成员代码...
};

这个方案适合你需要同时支持拷贝和移动语义的场景。


内容的提问来源于stack exchange,提问作者Hakim

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 18:55:14