含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
相关产品推荐
相关产品推荐

