值返回与引用返回(c++)

目录

值返回

引用返回

二者的区别

生命周期

可以安全引用返回的情况

返回函数参数(传入的引用)

返回成员变量

返回动态分配的对象(但通常是返回指针)

禁止返回的类型

返回局部变量

返回临时对象

返回局部指针指向的对象

复制代码试一下

总结


在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;
}

此代码可以帮助你观察与理解值返回与引用返回的区别

总结

场景 值返回 引用返回
返回计算结果 ✅ 推荐 ⚠️ 需确保对象有效
返回局部创建的对象 ✅ 安全 ❌ 绝对禁止
返回输入参数 ⚠️ 可能低效 ✅ 高效
返回静态数据 ⚠️ 可能拷贝 ✅ 高效
链式调用 ❌ 不能链式 ✅ 支持链式
函数修改参数 ❌ 不能修改 ✅ 可以修改
多线程安全 ✅ 线程安全 ⚠️ 需同步访问
相关推荐
csbysj202010 小时前
Java 日期时间处理详解
开发语言
我命由我1234510 小时前
Python Flask 开发 - Flask 快速上手(Flask 最简单的案例、Flask 处理跨域、Flask 基础接口)
服务器·开发语言·后端·python·学习·flask·学习方法
大飞记Python10 小时前
从零配置Python测试环境:详解路径、依赖与虚拟环境最佳实践
开发语言·python·环境配置·安装目录
zhougl99611 小时前
区分__proto__和prototype
开发语言·javascript·原型模式
weixin_4209476411 小时前
php composer update 指定包的分支非tag
开发语言·php·composer
一水鉴天11 小时前
整体设计 定稿 之6 完整设计文档讨论及定稿 之4 整体设计数据库设计规范(含两个版本)
开发语言·人工智能·架构
XFF不秃头11 小时前
【力扣刷题笔记-在排序数组中查找元素的第一个和最后一个位置】
c++·笔记·算法·leetcode
Evand J11 小时前
【EKF定位滤波例程】三维空间(XYZ)速度与位置观测与滤波(使用扩展卡尔曼滤波EKF),状态量和观测量都是非线性的。附MATLAB例程下载链接
开发语言·matlab
AM越.11 小时前
Java设计模式超详解--观察者设计模式
java·开发语言·设计模式