目录
在c++中函数可以返回值(by value)也可以返回引用(by reference)。
两者的根本区别在于返回的是对象的副本还是对象本身
值返回
返回对象的副本 ,调用者得到的是全新的独立对象。
cpp
// 值返回:返回类型不带&
string function1() { // 返回string(值)
string local = "hello would";
return local; // 返回local的副本
}
引用返回
返回对象的引用(别名) ,调用者得到的是已有对象的另一个名称,不创建新对象。
cpp
// 引用返回:返回类型带&
string& function2() { // 返回string&(引用)
static string global = "world";
return global; // 返回global的引用(别名)
}
// const引用返回
const string& function3() { // 返回const string&(常量引用)
static string global = "world";
return global; // 返回不能修改的引用
}
二者的区别
最主要的判断方式是其函数类型后是否跟着& 若其跟着&即为返回对象的引用 不创建新的对象
生命周期
值返回例子如下
cpp
string version1(const string& s1, const string& s2)
{
string temp;//创建局部变量temp(在栈上)
temp = s2 + s1 + s2;//计算s2+s1+s2,赋值给temp
return temp;//创建temp的副本(临时对象)作为返回值
}
//函数结束:temp被销毁(栈帧弹出)
//主函数中:用返回值初始化或赋值给result(调用拷贝构造函数或赋值运算符)
即可以得出version1返回的是值 并且在返回后temp被销毁 而其return的是temp的副本与temp本身的销毁无关 完全的独立
引用返回
version3 当函数结束后,temp就被销毁了,所以返回的引用将指向一个不再存在的对象,这会导致未定义行为。注意:不要返回局部变量的引用或指针
可以安全引用返回的情况
返回静态局部变量
cpp
const string& getDefaultName() {
static string defaultName = "Default"; // 静态变量
return defaultName; // 安全:生命周期为整个程序不会随着函数结束而销毁
}
返回函数参数(传入的引用)
cpp
string& appendStars(string& str) {
str += "***";
return str; // 安全:str的生命周期由调用者管理
}
返回成员变量
cpp
class Person {
private:
string name;
public:
const string& getName() const { return name; } // 安全
string& getName() { return name; } // 安全(但有风险)
};
返回动态分配的对象(但通常是返回指针)
cpp
string* createDynamicString() {
return new string("Dynamic"); // 返回指针,调用者需delete
}
禁止返回的类型
返回局部变量
cpp
const string& badFunction() {
string local = "Local"; // 局部变量
return local; // 致命错误!返回后将指向无效内存
}
返回临时对象
cpp
const string& badFunction2() {
return string("Temporary"); // 临时对象,语句结束就销毁
}
返回局部指针指向的对象
cpp
string& badFunction3() {
string* ptr = new string("Dynamic");
return *ptr; // 危险:内存泄漏风险,调用者不知道需要delete
}
总结 注意:不要返回局部变量的引用或指针
复制代码试一下
cpp
//strquote.cpp -- different designs
#include<iostream>
#include<string>
using namespace std;
string version1(const string& s1, const string& s2);
const string& version2(string& s1, const string& s2); //has side effect
const string& version3(string& s1, const string& s2); //bad design
int main()
{
string input;
string copy;
string result;
cout << "Enter a string: ";
getline(cin, input);
copy = input;
cout << "Your string as entered: " << input << endl;
result = version1(input, "***");
cout << "Your string enhanced: " << result << endl;
cout << "Your original string: " << input << endl;
result = version2(input, "###");
cout << "Your string enhanced: " << result << endl;
cout << "Your original string: " << input << endl;
cout << "Resetting original string.\n";
input = copy;
result = version3(input, "@@@");
cout << "Your string enhanced: " << result << endl;
cout << "Your original string: " << input << endl;
return 0;
}
string version1(const string& s1, const string& s2)
{
string temp;
temp = s2 + s1 + s2;
return temp;
}
const string& version2(string& s1, const string& s2) //has side effect
{
s1 = s2 + s1 + s2;
//safe to return reference passed to function
return s1;
}
const string& version3(string& s1, const string& s2) //bad design
{
string temp;
temp = s2 + s1 + s2;
//unsafe to return reference to local variable
return temp;
}
此代码可以帮助你观察与理解值返回与引用返回的区别
总结
| 场景 | 值返回 | 引用返回 |
|---|---|---|
| 返回计算结果 | ✅ 推荐 | ⚠️ 需确保对象有效 |
| 返回局部创建的对象 | ✅ 安全 | ❌ 绝对禁止 |
| 返回输入参数 | ⚠️ 可能低效 | ✅ 高效 |
| 返回静态数据 | ⚠️ 可能拷贝 | ✅ 高效 |
| 链式调用 | ❌ 不能链式 | ✅ 支持链式 |
| 函数修改参数 | ❌ 不能修改 | ✅ 可以修改 |
| 多线程安全 | ✅ 线程安全 | ⚠️ 需同步访问 |