Android C++系列:函数返回值注意事项

简介: 函数返回值就是使用return语句终止正在执行的函数,看是很简单的问题有什么说的呢?因为越是简单的问题里面越是有一些不易发现的坑。

image.png


1. 背景


函数返回值就是使用return语句终止正在执行的函数,看是很简单的问题有什么说的呢?因为越是简单的问题里面越是有一些不易发现的坑。


比如在循环中使用return语句:


bool findChar(const string &str, const char c){
  auto size = str.size();
  for(decltype(size) i = 0; i < size; i++){
    if(str[i] == c){
      return true;
    }
  }
}


看是有return语句,但是只有循环中满足特定条件才能正常返回,如果找不到的话实际上是没有返回值。编译器可能能检测出这个错误,也可能检测不出来,要看编译器的实现,好在大部分情况编译器甚至IDE可以帮我们检测出来,但是如果不幸我们用了检测不出来的编译器,可能会在运行时发生未定义行为错误。


2. 理解值是如何被返回的


类似于形参被初始化,函数返回一个值也是类似于变量初始化。最终是返回的值初始化调用点的一个临时量,这个临时量就是函数调用的结果。


如果函数返回的是局部变量,则返回值将被拷贝到调用点。


如果函数返回的是引用,因为引用只是它所引对象的别名,则不会将所引用的值拷贝到调用点。


那么问题来了,如果返回的引用引用了局部变量会发生什么?


答案是会发生错误,因为返回了未定义的值。


因为在方法体内,函数执行完成意味着局部变量存储的空间会被释放,局部变量的引用指向了非法内存区域。


举个栗子:


const string *getStr(){
​ string ret;
​ return ret; //返回局部对象的引用
​ //return "Hello"; //Hello是局部临时变量
}


如果函数体定义的是const string getStr()那么这么实现一点问题都没有,因为返回的是对象本身,会进行一次拷贝。

返回局部对象的指针也是类似的问题。


3. 返回类类型的函数


我们经常有看到有这样使用的场景:


std::vector<std:string> strs;
strs.begin().size();


当函数返回的是类类型,因为它的返回值可以继续参与运算,所以使用调用运算符可以继续调用函数返回结果对象的成员。

这个我们日常开发中并不少见。


4. 返回左值


如果函数返回的是引用的左值,那么我们可以为函数结果赋值:


int &getVal(int &i){
  return i;
}
void main(){
  int value = 100;
  getVal(value) = 200;
}


这里面看是怪怪的,但是其实是正确的。因为返回值是引用,所以调用是个左值,左值就是可以赋值。


但是要注意,如果返回的是常量引用,那么我们就不能再这么赋值了。


5. 返回列表


C++11中允许我们使用花括号包围的值的列表当返回值,初始化临时的vector:


std::vector<int> getValues(){
  return {1, 2,3,4};
}


不再需要我们手动去定义vector变量并初始化后再返回。


6. 返回数组指针


数组有个特性就是不能被拷贝,那么如果我们返回的是数组怎么办?怎么把返回值拷贝到调用点呢?


所以函数不能返回数组,但是可以返回数组指针或引用。


我们怎么定义一个返回数组指针或者引用的函数呢?有个比较简单的办法,就是使用类型别名:


typedef int arrT[10];//等价于using arrT = int[10];
arrT* fun(int i);


arrT是含有10个整数的数组的别名。


7. 总结


文本介绍了函数返回值的各种小细节:值是如何被返回,返回类类型怎么使用,返回左值引用,返回列表以及返回数组指针等。

目录
相关文章
|
6月前
|
存储 安全 编译器
给我介绍一些C++中引用的使用注意事项
C++引用是变量别名,简洁但易踩坑:必须初始化且不可重绑定;非const引用不能绑定右值;避免返回局部变量引用;不存在引用的数组或指针;注意const引用延长临时对象生命周期;区分引用声明与取地址符&。正确使用可提升代码安全与可读性。
422 5
|
存储 前端开发 C++
C++ 多线程之带返回值的线程处理函数
这篇文章介绍了在C++中使用`async`函数、`packaged_task`和`promise`三种方法来创建带返回值的线程处理函数。
733 6
|
Java Android开发 C++
🚀Android NDK开发实战!Java与C++混合编程,打造极致性能体验!📊
在Android应用开发中,追求卓越性能是不变的主题。本文介绍如何利用Android NDK(Native Development Kit)结合Java与C++进行混合编程,提升应用性能。从环境搭建到JNI接口设计,再到实战示例,全面展示NDK的优势与应用技巧,助你打造高性能应用。通过具体案例,如计算斐波那契数列,详细讲解Java与C++的协作流程,帮助开发者掌握NDK开发精髓,实现高效计算与硬件交互。
638 1
|
Java 调度 Android开发
Android经典实战之Kotlin的delay函数和Java中的Thread.sleep有什么不同?
本文介绍了 Kotlin 中的 `delay` 函数与 Java 中 `Thread.sleep` 方法的区别。两者均可暂停代码执行,但 `delay` 适用于协程,非阻塞且高效;`Thread.sleep` 则阻塞当前线程。理解这些差异有助于提高程序效率与可读性。
426 1
|
安全 Android开发 Kotlin
Android经典面试题之Kotlin中常见作用域函数
**Kotlin作用域函数概览**: `let`, `run`, `with`, `apply`, `also`. `let`安全调用并返回结果; `run`在上下文中执行代码并返回结果; `with`执行代码块,返回结果; `apply`配置对象后返回自身; `also`附加操作后返回自身
403 8
|
Java Android开发 C++
🚀Android NDK开发实战!Java与C++混合编程,打造极致性能体验!📊
【7月更文挑战第28天】在 Android 开发中, NDK 让 Java 与 C++ 混合编程成为可能, 从而提升应用性能。**为何选 NDK?** C++ 在执行效率与内存管理上优于 Java, 特别适合高性能需求场景。**环境搭建** 需 Android Studio 和 NDK, 工具如 CMake。**JNI** 构建 Java-C++ 交互, 通过声明 `native` 方法并在 C++ 中实现。**实战** 示例: 使用 C++ 计算斐波那契数列以提高效率。**总结** 混合编程增强性能, 但增加复杂性, 使用前需谨慎评估。
571 4
|
Android开发
Android面试题之自定义View注意事项
在Android开发中,自定义View主要分为四类:直接继承View重写onDraw,继承ViewGroup创建布局,扩展特定View如TextView,以及继承特定ViewGroup。实现时需注意:支持wrap_content通过onMeasure处理,支持padding需在onDraw或onMeasure/onLayout中处理。避免在View中使用Handler,使用post系列方法代替。记得在onDetachedFromWindow时停止线程和动画以防止内存泄漏。处理滑动嵌套时解决滑动冲突,并避免在onDraw中大量创建临时对象。
243 4
|
JSON Android开发 C++
Android c++ core guideline checker 应用
Android c++ core guideline checker 应用
213 0
|
JSON Android开发 数据格式
Android c++ core guideline checker 应用问题之JSON compilation database的定义如何解决
Android c++ core guideline checker 应用问题之JSON compilation database的定义如何解决
|
IDE 开发工具 Android开发
Android c++ core guideline checker 应用问题之clang-tidy 检查后发现的问题如何解决
Android c++ core guideline checker 应用问题之clang-tidy 检查后发现的问题如何解决