初始化后修改const引用的问题及解决方案探讨
用const引用替代getter的复制异常解决方法
有人提议用类内公开的const引用替代冗余的getter函数,示例代码如下:
class Test { private: std::vector<int> _x; public: const std::vector<int> & x = _x; };
这种写法在多数场景下表现正常,但复制子集时会出现异常。以下是完整测试代码:
#include <vector> #include <iostream> class Test { public: Test() { _x = {1,2,3,4}; } private: std::vector<int> _x; public: const std::vector<int> & x = _x; Test getSubset(int i, int j) { Test subset = *this; subset._x = {_x.begin() + i, _x.begin() + j}; return subset; }; void test() { std::cout << "x size: " << x.size() << ", _x size: " << _x.size() << std::endl; } }; int main( ){ Test t; t.test(); Test t2 = t.getSubset(1,2); t2.test(); }
程序输出:
x size: 4, _x size: 4 x size: 4, _x size: 1
可见返回的子集对象中,_x已被修改为大小1的vector,但公开的x引用仍指向原对象的_x,导致结果不符。这是因为默认复制构造函数会直接拷贝引用的地址,而非让新对象的x引用绑定到自身的_x。
除了定义传统getter函数外,还有以下几种解决方法:
自定义复制构造函数与赋值运算符
显式定义复制构造函数,在初始化列表中让新对象的x引用绑定到自身的_x;赋值运算符无需修改x(因为引用初始化后无法重新绑定,赋值时对象已完成初始化,x已经指向自身_x):class Test { public: Test() : x(_x) { _x = {1,2,3,4}; } // 自定义复制构造函数 Test(const Test& other) : _x(other._x), x(_x) {} // 自定义赋值运算符 Test& operator=(const Test& other) { if (this != &other) { _x = other._x; } return *this; } private: std::vector<int> _x; public: const std::vector<int> & x; // 原有的getSubset和test函数保留 };这样复制生成的新对象,
x会正确指向自身的_x,修改_x后x的访问结果会同步更新。用inline const成员函数替代引用
放弃成员引用,改用一个inline的const成员函数,写法简洁且编译器通常会将其优化为直接访问,效果接近成员引用但避免了复制问题:class Test { private: std::vector<int> _x; public: const std::vector<int>& x() const noexcept { return _x; } // 原有的构造函数、getSubset和test函数保留,注意test中调用改为x() void test() { std::cout << "x size: " << x().size() << ", _x size: " << _x.size() << std::endl; } };调用时只需将
t.x改为t.x(),既保持了简洁性,又保证了const安全性。使用成员函数模板(C++11及以上)
如果需要更灵活的类型适配,可以用模板函数封装访问逻辑,不过这个场景下必要性较低,仅作为扩展选项:class Test { private: std::vector<int> _x; public: template<typename T = const std::vector<int>> auto x() const noexcept -> const T& { return _x; } // 原有的其他成员函数保留,调用方式同inline函数 };
内容的提问来源于stack exchange,提问作者Nathaniel Bubis
相关产品推荐
相关产品推荐

