C++派生类const引用成员在list/vector迭代修改时不更新问题
问题根因
你遇到的问题核心是带引用成员的类默认拷贝语义不符合预期,底层逻辑如下:
- C++中的引用一旦完成初始化绑定,就无法再修改指向的目标
- 你没有为
Child类自定义拷贝构造函数,编译器会自动生成默认拷贝构造:它只会逐成员拷贝源对象的值,对于引用成员input,会直接把新对象的input绑定到源对象的inputs成员,而非新对象自身继承的inputs成员 - 你用
std::list<Child> test_lists = { test1, test2, test3 };初始化容器时,会对栈上的test1/test2/test3执行拷贝构造,生成容器内的3个新Child对象。这3个新对象的input引用全部绑定到栈上原对象的inputs,而非自身的inputs - 遍历调用
set_inputs时,修改的是容器内对象自身的inputs成员,但输出用的input引用指向的还是栈上未被修改的原对象的inputs,因此出现不同步的问题。单独使用test0时没有拷贝操作,input始终绑定自身的inputs,所以运行正常。
解决方案
下面给出3种可适配容器场景的方案,推荐优先使用第一种:
方案1:将引用成员改为成员函数(最优)
完全避免引用成员带来的拷贝语义问题,没有额外开销,兼容性最好:
class Child : public Parent { public: Child() = default; void set_inputs(const double& X) { inputs = X; } // 改为成员函数,调用时返回当前对象自身的inputs const double& input() const { return inputs; } }; // 调用处对应修改为 cout << t->input() << endl;
方案2:显式定义拷贝构造与拷贝赋值(适合必须保留类引用/指针成员的场景)
注意引用成员无法被重新赋值,因此如果需要支持拷贝赋值,建议将引用改为指针:
class Child : public Parent { public: Child() = default; // 自定义拷贝构造,手动绑定input到自身的inputs Child(const Child& other) { inputs = other.inputs; input = &inputs; // 这里把input改成了const double*类型 } // 自定义拷贝赋值 Child& operator=(const Child& other) { if (this != &other) { inputs = other.inputs; // 指针可以重新赋值,引用做不到这一点 input = &inputs; } return *this; } void set_inputs(const double& X) { inputs = X; } public: const double* input = &inputs; }; // 调用处对应修改为 cout << *(t->input) << endl;
方案3:容器存储智能指针避免对象拷贝
不需要修改Child类的原有定义,适合对象较大、拷贝开销高的场景:
// 容器改为存储unique_ptr<Child> std::list<std::unique_ptr<Child>> test_lists; test_lists.push_back(std::make_unique<Child>()); test_lists.push_back(std::make_unique<Child>()); test_lists.push_back(std::make_unique<Child>()); // 遍历逻辑不变 for (auto& t : test_lists) { t->set_inputs(X1); cout << t->input << endl; }
内容的提问来源于stack exchange,提问作者lefe
相关产品推荐
相关产品推荐

