定义一个指向对象的指针或则引用不会调用构造函数和析构函数。

  

首先,强调一点,和函数传参一样,函数返回时也会做一个拷贝。从某种角度上看,和传参一样,也分为三种:

(1)返回值:返回任意类型的数据类型,会将返回数据做一个拷贝(副本)赋值给变量(return语句后边的变量会生成一个副本给一个临时量,这个临时量会将返回值带给主调函数,当调用点处的表达式结束后该临时变量就被释放掉了,而且定义函数时指定的返回值类型实际上指定的就是这个临时变量的类型。还值得注意的一点是临时量没有具体的内存地址,也就是它都根本没有装值的地方,因此不能被修改,你想去改也不知道去哪里改,所以他是一个右值);由于需要拷贝,所以对于复杂对象这种方式效率比较低(在返回类类型时,没有返回值优化的时候,临时量会通过拷贝构造函数拷贝函数中定义的局部对象,在临时量被释放掉时会调用析构函数;如果是返回值优化,则不会生成临时量,该局部变量的值会直接放在调用点处等号左侧的变量的内存中。);例如:int test(){}或者 Point test(){}
(2)返回指针:返回一个指针,也叫指针类型的函数。

 

1 int* test02()
2 {
3     static int a=0;
4     return &a;
5 }

 

在上面的程序中,函数返回的是局部变量的地址值,它是一个值,因此是右值。

 

1 int* fun()
2 {
3     static int a = 0;
4     cout << &a << endl;
5     static int* p = &a;
6     return p;
7 }

 

在上面的程序中,函数返回的是p指向的地址值,它是一个值,因此是右值。

并且返回类类型的指针的时候不会调用拷贝构造函数和析构函数;例如:int *test(){} 或者 Point *test(){}。如果返回局部变量的指针,则在调用点等号右侧的指针会因为函数内部局部变量的内存释放而变成野指针。对于X64系统来讲,可能会在第一次打印输出的时候打印出局部变量的值。因为函数调用返回后栈上的数据并没有被清空,而是程序失去了对栈所在内存的控制权第二次输出的时候已经被别的数据覆盖了,所以输出的内容是不可控的。

注意:

  • 函数返回的指针是临时量是右值
  • 不要将非静态局部地址用作函数返回值:因为局部地址在离开函数后就失效了。
  • 可以在函数中用动态内存分配(new)的地址返回,但需要注意内存分配和释放不在同一级别,不要忘记释放,否则内存泄露(堆区内存程序员忘记释放,以后再也是用不了这块内存);
  • 可以在主调函数中定义数组,函数中对该数组进行操作,然后返回其中一个元素的地址;

(3)返回引用:返回一个引用,也叫返回引用类型的函数,在返回时会返回局部变量的别名,可以认为函数在返回的时候创建了一个引用,该引用就是局部变量的别名,可以对它修改,因此是右值

 

 1 int& fun()
 2 {
 3     static int a = 0;
 4     return a;
 5 }
 6 
 7 int main()
 8 {
 9     cout << fun() << endl;
10     fun() = 100;
11     cout << fun() << endl;
12     system("pause");
13     return 0;
14 }

 

运行结果:

 

 但如果返回的是局部变量的引用:

 1 int& fun()
 2 {
 3     int a = 10;
 4     return a;
 5 }
 6 
 7 int main()
 8 {
 9     cout << fun() << endl;
10     fun() = 100;
11     cout << fun() << endl;//再一次调用时fun()的局部变量被重新初始化
12     system("pause");
13     return 0;
14 }

 

同时,该引用不会调用拷贝构造函数和析构函数;例如:int &test(){}或者 Point &test(){}

如果返回值是指针或则引用,栈局部对象会被释放掉,就会出现临时的指针或则引用失去指向的对象,变成野指针(这里姑且认为引用是一个指针常量),会出现不可预料的问题

 

(3)返回字符串:

 

通过 char* s = “Hello”; 的方式得到的是一个字符串常量 Hello,存放在只读数据段(相当于常量,在程序运行的时候不会被释放)把该字符串常量的只读数据段的首地址赋值给了指针 s,所以函数返回时,该字符串常量所在的内存不会被回收,所以能正确地通过指针访问。

 

 1 #include <iostream>
 2 using namespace std;
 3  
 4 char *fun1() {
 5   char *s="hello";
 6   return s;//ok
 7 }
 8  
 9 int main() {
10   char *c1 = fun1();
11   cout<<c1<<endl;
12   //常量,无法在修改 
13   
14   return 0;
15 }

参考文章:

(84条消息) C++函数返回值_赶路人儿的博客-CSDN博客

 

posted on 2023-06-02 20:37  小凉拖  阅读(266)  评论(0编辑  收藏  举报