返回值处理

在代码的编译运行时,常常需要一个函数最后返回多个结果,返回的结果中可能是类型相同的也可能时不同的,多个返回类型已经不能或者用现有的方式能很好的解决这个问题,如果是同一类型的返回值,我们可以返回数组,如果是多个不同的返回值,那么已经显得比较乏力,如何处理返回值已经成为了重要的问题。

  • 返回多个值方式1:将其封装为一个类再返回

我们可以将所有需要返回的数据类型扔进一个结构体,在返回时只需要返回一个结构体即可。

示例代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

#include <iostream>
#include <string>

struct Returntype//我们将需要返回的值放入结构体中,只需要添加自己想要的返回值内容就可以
{
int x;
int y;
std::string s1;
};

Returntype Example(int a,int b,std::string s)
{
a=a+10;
b=a+15;
name=s;

Returntype r1;
r1.x=a;
r1.y=b;
r1.s1=name;
return r1;
}

int main()
{
int a=1;
int b=1;
std::string name="LYsnowQ";

Returntype Re;
Re=Example(a,b,name);

return 0;
}

  • 返回方式2:使用地址指针传参

在传参时直接将地址传入,&取地址符号相当于在函数内部直接修改参数值,所以不需要返回值即可直接对main参数进行修改,或者可以使用指针传入变量地址,再在内部解引用后进行赋值操作。

两者区别在于:取地址必须传入有效的参数,而指针可以传入空指针(nullptr)

示例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44


#include <iostream>
#include <string>
//以下是使用引用
void Example(int& a,int& b,std::string& s)
{
a=a+10;
b=a+15;
s="LYsnowQ";
}

int main()
{
int a=1;
int b=1;
std::string name;

Example(a,b,name);

return 0;
}
//以下是使用指针

void Example(int* a,int* b,std::string* s)
{
if(a!=0)
*a=*a+10;
if(b!=0)
*b=*a+15;
if(s!=0)
*s="LYsnowQ";
}

int main()
{
int a=1;
int b=1;
std::string name;

Example(&a,&b,&name);

return 0;
}
  • 返回方式3:使用数组,如array和vector

array和vector的区别在array是直接在栈上进行操作,返回时要快于vector,因为vector底层是在堆上进行操作。array在使用时还需要规定长度,所以在使用便携性能上array不如vector方便

而array和vector的共同缺陷是只能返回相同类型的变量,而多个类型混合时显得乏力

示例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48

#include <iostream>
#include <string>
#include <array>
#include <vector>

std::array<int,2> Example(int a, int b)
{
a = a + 10;
b = a + 15;

std::array<int,2> results;
results[0] = a;
results[1] = b;
return results;
}

int main()
{
int a = 1;
int b = 1;

std::array<int ,2> Re = Example(a, b);

return 0;
}

//使用vector
std::vector<int> Example(int a, int b)
{
a = a + 10;
b = a + 15;

std::vector<int> results;
results[0] = a;
results[1] = b;
return results;
}

int main()
{
int a = 1;
int b = 1;

std::vector<int> Re = Example(a, b);

return 0;
}
  • 返回方式4:使用pair或者tuple

tuple的本质是一个类。它可以包含x个变量,而pair一次只能支持两个量,但是pair可以嵌套多个量

示例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53

#include <iostream>
#include <string>
#include <tuple>

//以下为tuple
std::tuple<int,int,std::string> Example(int& a, int& b, std::string& s)
{
a = a + 10;
b = a + 15;
s = "LYsnowQ";
return std::make_tuple(a, b, s);
}

int main()
{
int a = 1;
int b = 1;
std::string name;

std::tuple<int,int,std::string> T=Example(a, b, name);

//如果想取出
std::string name2 = std::get<2>(T);
return 0;
}
//以下为pair

#include <iostream>
#include <string>
#include <tuple>


std::pair<int, std::string> Example(int& a,std::string& s)
{
a = a + 10;
s = "LYsnowQ";
return std::make_pair(a,s);
}

int main()
{
int a = 1;
int b = 1;
std::string name;

std::pair<int,std::string> P = Example(a,name);
//访问内容时使用first和second或者tie
a=P.first;
name=P.second;
std::tie(a,name)=Example(a,name);
return 0;
}
  • 返回方式5:结构化绑定(c++17特性)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <iostream>
#include <string>
#include <tuple>

std::tuple<std::string,int> CreatePersion()//pair同样适用
{
return {"LYsnowQ",24};
}

int main()
{
auto person = CreatPerson;
std::string& name = std::get<0>(person);
int age = std::get<0>(person);
//或者
auto[name, age] = CreatPerson();
}

综上来说,在返回多个值时,最直观的使用结构体去返回,可以提高代码的可读性,然而在性能上使用取地址符更好的节约性能开支,在pair和tuple中代码的可读性不高且较为复杂,在vector和array中存在着无法返回多个不同变量的限制。在使用结构化绑定时也会显得简洁好懂。


资料来源

youtube上the cherno的c++系列