c++函数引用

由于使用c++太少,在项目中定义成员函数时,想着应该返回vector<string>&还是vector<string>;思考上升到函数返回对象时,经历几次构造函数。

依稀记得函数返回对象,需要经过生成一个临时对象(call copy constructor),然后根据语句是变量声明还是复制分别调用copy constructor 或者assign operator;

分别使用g++(4.84.xx)和VS2010+实验以下code:

 1 #include "stdafx.h"
 2 #include <stdlib.h>
 3 #include <vector>
 4 #include <iostream>
 5 using namespace std;
 6 class A {
 7 public:
 8     int a;
 9     A() :a(10) {}
10     ~A()
11     {
12         //printf("~A(),addr=%p\n",this);
13     }
14     A(const A& inst)
15     {
16         printf("copy constructor\n");
17         this->a = inst.a;
18     }
19     A& operator =(const A& inst)
20     {
21         printf("operator =\n");
22         this->a = inst.a;
23         return *this;
24     }
25     int& getA()
26     {
27         return a;
28     }
29 };
30 A func()
31 {
32     A a;
33     a.a = 3;
34     printf("func() a.a addr=0x%p\n", &a.a);
35     return a;
36 }
37 int main()
38 {
39     printf("test A a = func()\n");
40     A a = func();
41     A a1 = func();
42     printf("a.a,a1.a addr=0x%p, 0x%p\n", &a.a, &a1.a);
43     //A& b = func();//intial value of reference to non-const must be a lvalue
44     int& c = a.getA();
45     a.a = 100;
46     printf("%d\n",c);
47     A* b = new A();
48     int& c1 = b->getA();
49     b->a = 100;
50     printf("delete before %d\n", c1);
51     delete b;
52     printf("delete after %d\n", c1);
53     system("pause");
54     return 0;
55 }
View Code

1、结果发现,在release版本(准确的说法是打开了优化项),A a = func();这种形式被编译器优化,不会调用copy constructor,即使a=func()也只有一次assign operator(不管是否打开优化选项);

禁止优化项,得到的结果,A a = func();调用一次copy constructor。

2、另外考虑一个对象的成员函数什么时候应该使用引用返回成员变量呢?

百度搜索,找不到想要的解答;自己思考,引用返回成员变量,会导致它的作用域发生变化,如果对象被释放,可能引起资源被释放还在使用的问题(例如野指针);

因此,我觉得可以使用引用返回例如vector<string>的对象,但开发者应该注意使用者和对象的生存周期(string.data()/c_str()就是这个意思);另外在提供对外api时,如果使用引用对象返回的形式,一定需要注明该对象的生命周期。

期望有大神可以对这个问题提出经验之谈,本人实在缺乏经验。标准库给出了例子(string),写code大局上遵守低耦合高内聚,易调试,易扩展(框架,灵活性);细处能通就是赢,鬼斧神工的细节是修改出来的不是写出来的。

以下是打开优化时,VS2017的输出结果(gcc的%p会自动加上0x):

test A a = func()
func() a.a addr=0x0034FAD4
func() a.a addr=0x0034FAD0
a.a,a1.a addr=0x0034FAD4, 0x0034FAD0
100
delete before 100
delete after 7171672

3、引用做入参的有趣发现

写函数时,如果不想发生constructor,总会想到引用(&),如果觉得入参不需要被修改,总会想到const,加与不加的区别,我认为只有入参可变或不可变, 没有其他区别;

因为懒,不写const,会导致有时传参不那么方便(cahr*传给const string&):

在做一个项目时,发现其他一点东西:入参加上&,如果带上const,那么支持隐式类型转换;

void testIntRef(int& ref)
{
	;
}
void testConstIntRef(const int& ref)
{
	;
}
void testInt(int i)
{
	;
}
void testConstInt(const int i)
{
	;
}
void testRef()
{
	int test = 3;
	testIntRef(test);
	testConstIntRef(3);
	char a = 'a';
	//testIntRef(a);//compile error
	testConstIntRef(a);//implict convert
	testInt(a);
	testConstInt(a);
}
声明函数时,面对string(实参传入char*),或者一些自定义类时,了解这点挺重要吧!
posted @ 2018-03-12 22:21  green_crosswalk  阅读(435)  评论(0编辑  收藏  举报