函数返回const引用,使用const修饰变量接收
函数返回const引用,使用const修饰变量接收
1、背景
想获取红绿灯时长数组并添加新的值。有个函数是返回红绿灯时长数组的。函数返回类型为const引用,我使用无修饰的变量接收。但是感觉有些问题,并且之前看到const变量变成非const还需要使用const_cast。
查了一下copilot,确实需要注意。
2、问题分析
GetPassTimeVec函数原型如下:
const std::vector<uint32_t>& CalLightLength::GetPassTimeVec()
{return m_passTime;
}
我在其他代码位置获取这个函数,并使用无修饰变量接收,写法如下
// CalLightLength calLightLength; 这个对象非单例类对象,是从前往后都存在的实例化对象,仅做演示。
std::vector<uint32_t> vec = calLightLength.GetPassTimeVec();
这个代码写出来感觉有点不对劲,因为没有做const_cast解除const。
问了下copilot,能否哟个无修饰变量接收函数const引用返回值。copilot回答如下:
函数返回const引用,用非const变量接收有问题吗
是的,用非
const
变量接收const
引用的返回值可能会带来一些问题,主要体现在 编译错误 和 潜在的未定义行为 这两方面。1. 编译错误
如果函数返回的是
const
引用,而你尝试用 非const
引用 或 非const
变量 进行接收,编译器通常会报错。例如:cpp
const int& getValue() {static int value = 42;return value; }int& ref = getValue(); // ❌错误:不能用非 const 引用接收 const 引用返回值
这里
getValue()
返回const int&
,但ref
是int&
,试图去掉const
限制,违反了const
保护规则,编译器会报错。2. 未定义行为
如果使用 非
const
变量 接收const
引用返回值,并进行 修改,可能会导致 未定义行为:cpp
const int& getValue() {static int value = 42;return value; }int ref = getValue(); // ✅可以编译,但有潜在问题 ref = 100; // ⚠️此时只是修改了 `ref`,不会影响 `value`
这里
ref
是 按值接收(不是引用),因此ref
是getValue()
返回值的 拷贝,修改ref
并不会改变value
,但可能会让人误以为value
被修改了。3. 正确的做法
如果不希望修改返回值,应该使用
const
引用接收:cpp
const int& ref = getValue(); // ✅正确 std::cout << ref << std::endl;
如果确实需要修改返回值,可以考虑 去掉
const
或使用const_cast
:cpp
int& ref = const_cast<int&>(getValue()); // ⚠️危险,可能导致未定义行为 ref = 100; // 这里修改了 `value`
但请谨慎使用
const_cast
,它会破坏const
保护,可能导致不可预知的结果!总结
- 不能用非
const
引用接收const
引用返回值,否则编译会报错。- 用非
const
变量接收const
引用返回值,不会直接导致错误,但会创建一个 拷贝,修改时不会影响原值。- 推荐用
const
引用接收const
引用返回值,避免拷贝,提高性能,同时保证const
语义。
针对回答中的如果使用非修饰的变量接收函数const引用返回值,可以编译,但有潜在问题。此时只是修改了 ref,不会影响value。下面验证一下,看看能不能复现问题。
下面是测试代码
std::vector<int> g_vec;void SetVec(std::vector<int> vec) {g_vec.assign(vec.begin(), vec.end());
}const std::vector<int> &GetVec() {return g_vec;
}int main() {std::vector<int> vec = {3, 2, 1, 5, 6, 7, 89};SetVec(vec);std::vector<int> vecCopy = GetVec();std::vector<int> vecAdd = {10, 11};vecCopy.insert(vecCopy.end(), vecAdd.begin(), vecAdd.end());for (int i = 0; i < g_vec.size(); i++) {printf("%d ", g_vec[i]);}return 0;
}
// 打印信息
// 3 2 1 5 6 7 89
和copilot的表示一样,不会对原来的g_vec有影响。那么copilot表述的可能有潜在风险应该指的是没有实现预期的功能。
如果改变GetVec函数的实现形式,可以实现改变g_vec的功能。代码如下:
修改点两处:
// 将返回值由const改成非const
std::vector<int> &GetVec() {return g_vec;
}// 用引用接收GetVec函数返回值
std::vector<int>& vecCopy = GetVec();// 打印信息
// 3 2 1 5 6 7 89 10 11
那么为什么不用const引用接收GetVec函数const引用返回值呢?因为在调用处需要更改g_vec内容,不能使用const,所以就需要更改GetVec函数定义形式。
以上就梳理一些const相关的知识点。