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

含const引用成员的类使用std::vector::emplace编译失败问题

含引用成员的类在vector::emplace编译失败,emplace_back却正常的原因及解决办法

问题根源

你遇到的差异源于std::vector两个方法的内部操作逻辑不同:

  • emplace_back在你调用reserve(10)后,直接在vector预留的尾部空闲内存中构造新对象,不需要移动任何已有元素,因此不会用到类的赋值运算符。
  • emplace插入到非末尾位置时,vector需要将插入点之后的所有元素向后移动(实际执行移动赋值操作)以腾出空间。但你的类A包含const Handle&类型成员,C++标准规定:类存在引用成员时,编译器会隐式删除它的拷贝赋值运算符和移动赋值运算符,导致vector无法完成元素移动,最终编译报错。

解决方案

方案1:将引用成员改为指针/智能指针

把const Handle&替换为const Handle*(或std::shared_ptr<const Handle>),类会自动生成默认赋值运算符,emplace操作即可正常执行:

#include <vector>

class Handle
{
    int do_something();
};

class A
{
public:
    A(int a, float d, const Handle* h) : a_(a), d_(d), h_(h) {}
private:
    int a_;
    float d_;
    const Handle* h_; // 替换为指针
};

int main()
{
    Handle h;
    std::vector<A> foo;
    foo.reserve(10);
    foo.emplace_back(3, 4.5, &h); 
    foo.emplace(foo.begin() + 3, 3, 4.5, &h); // 正常编译
}

方案2:改用无需移动元素的容器

如果必须保留引用成员,可以使用std::list这类链表结构的容器。list的emplace插入仅修改节点指针,不需要移动元素本身,不受赋值运算符缺失的影响:

#include <list>

class Handle
{
    int do_something();
};

class A
{
public:
    A(int a, float d, const Handle& h) : a_(a), d_(d), h_(h) {}
private:
    int a_;
    float d_;
    const Handle& h_;
};

int main()
{
    Handle h;
    std::list<A> foo;
    foo.emplace_back(3, 4.5, h);
    auto it = foo.begin();
    std::advance(it, 3);
    foo.emplace(it, 3, 4.5, h); // 正常编译
}

方案3:手动实现赋值运算符(不推荐)

若一定要保留引用成员且使用vector,可以手动为类A实现赋值运算符,但需注意引用无法重新绑定,赋值只能修改引用指向对象的内容,而非改变引用本身的指向。这种方式逻辑易出错,仅适合特殊场景:

#include <vector>

class Handle
{
public:
    int do_something() { return 0; }
    void set_value(int val) { value = val; }
    int value = 0;
};

class A
{
public:
    A(int a, float d, const Handle& h) : a_(a), d_(d), h_(h) {}

    A& operator=(const A& other) {
        if (this != &other) {
            a_ = other.a_;
            d_ = other.d_;
            // 仅修改引用指向对象的内容,无法重新绑定引用
            const_cast<Handle&>(h_).set_value(other.h_.value);
        }
        return *this;
    }

private:
    int a_;
    float d_;
    const Handle& h_;
};

int main()
{
    Handle h;
    std::vector<A> foo;
    foo.reserve(10);
    foo.emplace_back(3, 4.5, h);
    foo.emplace(foo.begin() + 3, 3, 4.5, h); // 可编译,但逻辑需自行保证
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 14:17:33