C++中返回类型与return语句

2023-09-17 02:05:32

C++中返回类型与return语句

有、无返回值的函数及其return语句
无返回值(函数声明中,返回值类型为void)的函数,如果其中没有任何return语句也是正确的,编译器会自动在函数结束处补上隐式的return;语句。如果这种void函数内部出现显式的return;,其作用是表示该函数在此处将控制权交还给主调函数。
除void函数外,其他函数必须显式地返回与声明中返回值类型相同(或可以转换为该类型)的值。
函数把值返回给调用处的细节原理
函数把值返回给外部调用处的实现方法细节与从外部实参传递值给函数形参的方法细节完全一样。本质上是用已有值(传参中的实参,返回中的返回值)初始化一个临时量(传参中的形参,返回中的函数调用点)。因此对象的初始化规则在函数返回过程中仍然适用。

1 函数返回局部变量给外部
本质上是将函数内局部变量的值拷贝给函数调用点,用来初始化(外部)调用点的临时对象。

2 函数返回引用给外部
引用是对象的别名,因此此时函数对外返回的是对象本身,而不是拷贝一个值给外部副本。因此要特别注意,千万不能返回函数内部局部对象的引用和指针。因为函数在结束调用后局部变量就会被销毁,这时被函数给返回到外部的局部变量对象(引用)将不再绑定有效的内存区域。

综上可知,函数要想对外返回引用(或指针),只能返回那种在函数调用之前已经存在了的对象的引用(或指向该对象的指针)

范例:

//函数对外返回引用的正确用法
const string &shorterStr(const string &s1, const string &s2) { //挑出两个string对象中较短的那个,返回其引用
    return s1.size() <= s2.size() ? s1 : s2; //因为s1和s2绑定的对象都是在调用函数前就已经存在的了,因此函数对外返回这种对象的引用不会产生问题
}

//以下写法严重错误,这个函数试图返回局部对象的引用
const string &manip() {
    string ret;
    if (!ret.empty()) {
        return ret; //❌,试图返回局部对象的引用
    } else {
        return "Empty"; //❌,"Empty"也是一个局部临时量,并且以引用的方式传出,在函数结束调用后该临时量会被销毁,使得外部调用点的引用不再绑定具体对象
    }
}

//以下写法严重错误,不能返回一个指向局部对象的指针
int *funcIp(int var) {
    int i = 10;
    int *ip = &(i + var); //i + var对象是一个临时量,结束调用后销毁,对外返回的指针无法指向确定的内存
    return ip;
}

返回类类型的函数可以连续调用
返回类类型(类的对象或其引用,或指向类的对象的指针)的函数,可以在其调用处继续使用调用运算符去调用该类的其他函数,如下例:

const string &shorterStr(const string &s1, const string &s2) { //此函数返回的是一个string对象的引用
	return s1.size() <= s2.size() ? s1 : s2; 
}
string s1 = "aaaa";
string s2 = "bbb";
auto sz = shorterStr(s1, s2).size(); //shoterStr(s1, s2)返回的是一个string对象(s2),该对象有size()成员函数,因此可以在shoterStr()的返回处再继续调用size(),这个调用结束后,返回的是一个size_t类型值对象,由auto类型对象sz接收

引用返回左值
调用一个返回引用的函数,在调用处得到左值(左值可以放在赋值号左边用来被赋值)
调用返回其他类型的函数,在调用处得到右值(右值可以放在赋值号右边用来赋值)
可以像使用其他左值那样来使用返回左值(返回引用)的函数调用,特别是能为返回类型是非常量引用的函数结果进行赋值。如下例:
但如果函数的返回值类型是常量引用,就不能给调用结果进行赋值了,这是常量特性所决定的

char &get_val(string &str, string::size_type ix) { //该函数的返回值类型是非常量引用,其返回结果可以在调用处被当作左值
    return str[ix]; //假定索引值ix一定合法
}

const string &shorterStr(const string &s1, const string &s2) { //此函数返回的是常量引用
    return s1.size() <= s2.size() ? s1 : s2; 
}

int main() {
    string s("a value");
    cout << s << endl; //输出:a value
    get_val(s, 0) = 'A'; //get_val的返回结果在此处被当作左值,因为它的返回值类型是非常量引用,可以完成这里的赋值操作,将s[0]的值改为A
    cout << s << endl; //输出:A value
    shoterStr("hi", "bye") = "X"; //❌,返回的是常量引用(也就是常量对象),不能被修改,因此也不能这样作为左值使用
    return 0;
}

该文章会更新,欢迎大家批评指正。

推荐一个零声学院的C++服务器开发课程,个人觉得老师讲得不错,
分享给大家:Linux,Nginx,ZeroMQ,MySQL,Redis,
fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,
TCP/IP,协程,DPDK等技术内容
点击立即学习:C/C++后台高级服务器课程

更多推荐

11、Kubernetes核心技术 - Service

目录一、概述二、Endpoint三、Service资源清单四、Service类型4.1、ClusterIP4.2、NodePort4.3、LoadBalancer4.4、ExternalName五、Service使用5.1、ClusterIP5.1.1、定义Pod资源清单5.1.2、创建Pod5.1.3、定义Servi

【从零学习python 】74. UDP网络程序:端口问题与绑定信息详解

文章目录udp网络程序-端口问题UDP绑定信息总结进阶案例udp网络程序-端口问题在运行UDP网络程序时,会遇到端口号会变化的情况。每次重新运行网络程序后,可以观察到运行中的“网络调试助手”显示的数字是不同的。这是因为该数字标识了网络程序的唯一性,系统在重新运行时会随机分配端口号。需要注意的是,在网络程序运行过程中,该

如何从市场上几千只股票中快速选出满意的股票

个人账户实现股票量化程序化自动交易,券商有接口,门槛已降低_股票程序交易接口的博客-CSDN博客像上面的例子,如果按照市面上常见的可转债万3或万2不免5,人工操作+费率限制,这种情况就不要想,根本没机会,有了自动交易这把利器,再加python强大的支持库,能发挥的想像空间实在太大了,目前来看,机会是有,但后期用程序交易

【计算机网络 - 自顶向下方法】计算机网络和因特网

目录1.WhatistheInternet?1.1因特网的具体构成1.2因特网的功能2.Networkcore2.1基本介绍2.2分组交换2.2.1序列化时延2.2.2排队延迟和丢包2.2.3分组交换的优缺点2.3电路交换2.3.1基本概念2.3.2电路交换网络中的复用2.3.3电路交换文件传输时间2.3.4分组交换与

SpringBoot整合Redis,基于Jedis实现redis各种操作

前言(三步教你学会redis,主打一个实用)springboot整合redis步骤,并基于jedis对redis数据库进行相关操作,最后分享非常好用、功能非常全的redis工具类。第一步:导入maven依赖<!--springboot整合redis--><dependency><groupId>org.springfr

C++11的半同步半异步线程池

C++11的半同步半异步线程池简介同步队列Take函数Add函数Stop函数SyncQueue完整代码线程池主函数测试简介半同步半异步线程池用的比较多,实现也比较简单。其中同步层包括同步服务层和排队层,指的是将接收的任务排队,将所有的任务排队到一个队列中,等待处理;异步层指多个线程处理任务,异步处理层从同步层取出任务,

shell编程之循环

循环是当循环控制条件为真时,一系列命令迭代执行的代码块。1、for循环语法:forargin[list]这是shell中最基本的循环结构,它与C语言形式的循环有着明显的不同。forargin[list]docommand(s)...done在循环的过程中,arg会从list中连续获得每一个变量的值。forargin"$

深拷贝与浅拷贝,就是这么简单

目录1.拷贝的概念2.浅拷贝2.1.浅拷贝的定义2.2.浅拷贝的实现方式2.3在内存中:3.深拷贝3.1.深拷贝的定义3.2.深拷贝的实现方式3.3在内存中4.深拷贝与浅拷贝的区别5.原型模式与深浅拷贝的关系6.总结1.拷贝的概念在编程中,拷贝(或复制)是常见的操作之一。拷贝操作用于创建一个新对象或数据结构,使其具有与

Mybatis-Plus入门(1)

单表的CRUD功能代码重复度很高,也没有什么难度。而这部分代码量往往比较大,开发起来比较费时。因此,目前企业中都会使用一些组件来简化或省略单表的CRUD开发工作。目前在国内使用较多的一个组件就是MybatisPlus.官方网站如下:简介|MyBatis-Plus当然,MybatisPlus不仅仅可以简化单表操作,而且还

【NLP入门教程】目录

当今,自然语言处理(NaturalLanguageProcessing,NLP)已经成为计算机科学与人工智能领域的重要研究方向之一。它涉及计算机如何理解、分析和生成人类语言,使得计算机可以与人类进行自然而流畅的交流。NLP的应用范围广泛,涵盖机器翻译、文本分类、情感分析、问答系统、语音识别等诸多领域。本教程旨在为初学者

【完全攻略】畅游NLP海洋:HuggingFace的快速入门

目录前言一、HuggingFace介绍1-1、HuggingFace的介绍1-2、安装二、Tokenizer分词库:分词工具2-0、加载BertTokenizer:需要传入预训练模型的名字2-1、使用Tokenizer对句子编码:2-2、使用增强Tokenizer对句子编码:2-3、批量编码单个句子:2-4、添加新词:

热文推荐