C++----局部静态对象和函数

来源:互联网 发布:免费的看书软件 编辑:程序博客网 时间:2024/05/29 08:01

局部静态对象

某些时候,有必要令局部变量的生命周期贯穿函数调用之后的时间。可以将局部变量定义成static类型从而获得这样的对象。局部静态对象(local static object)在程序的执行路径第一次经过对象定义语句是初始化,并且直到程序终止才被销毁,在此期间及时对象所在的函数结束执行也不会对它有影响。
举个例子,下面的函数统计它自己被调用了多少次:

size_t count_calls(){    static size_t ctr = 0;//调用结束后,这个值仍然有效    return ++ctr;}int main(){    for(size_t i = 0; i != 10; ++i)        cout << count_calls() << endl;    return 0;}

函数参数传递

和其他变量一样,形参的类型决定了形参和实参的交互方式。如果形参是引用类型,它将绑定到对应的实参是,否则,将实参的值拷贝后赋给形参。

void reset(int &i){    i = 0;}int j = 42;reset()j;cout << "j=" <<j <<endl;    //输出j=0

使用引用避免拷贝

拷贝大的类类型对象或者容器对象比较低效,甚至有的类类型根本就不支持拷贝操作。当某种类型不支持拷贝操作时,函数只能通过引用形参访问该类型的对象。
比如,我们准备编写一个函数比较两个string对象的长度。因为string对象可能会非常长,所以应该避免直接拷贝它们~

bool isshorter(const string &s1, const string &s2){    return s1.size() < s2.size();}

数组引用形参

C++语言允许将变量定义成数组的引用,基于同样的道理,形参也可以是数组的引用。此时,引用形参绑定到对应的实参上,也就是绑定到数组上:

void print(int ($arr)[10]){    for(auto elem:arr)        cout <<elem<<endl;}

&arr两端的括号不能少哟。这表示arr是具有10个整数的整型数组的引用~(这里就能限定数组的大小了)

int i = 0, j[2]={0,1};int k[10] = {0,1,2,3,4,5,6,7,8,9};print(&i);  //wrongprint(j);   //wrongprint(k);   //right

传递多维数组

在C++语言中实际没有真正的多维数组,所谓多维数组其实是数组的数组。
和所以数组一样,当将多维数组传递给函数时,真正传递的是指向数组首元素的指针。因为我们处理的是数组的数组,所以首元素本身就是一个数组,指针就是一个指向数组的指针。数组第二维(以及后面所以维度)的大小都是数组类型的一部分,不能省略:

void print(int (*matrix)[10]. int rowSize){/*...*/}

再次强调,*matrix两端括号不可少~

int *matrix[10];    //10个指针构成的数组int (*matrix)[10];  //指向含有10个整数的数组的指针

我们也可以使用数组的语法定义函数,此时编译器会一如既往地忽略掉第一个维度,所以最好不要把它包括在形参列表内:

//等价定义coid print(int matrix[][10], int rowSize){/*...*/}

不要返回局部对象的引用或指针

函数完成后,它所占用的存储空间也随之被释放掉。因此,函数终止意味着局部变量的引用将指向不再有效地内存区域:

//严重错误:这个函数试图返回局部对象的引用const string &manip(){    string ret;    if(!ret.empty())        return ret;      //错误:返回局部对象的引用;    else        return "Empty";  //错误:“Empty”是一个局部临时量}

列表初始化返回值

C++11新标准规定,函数可以返回花括号包围的值的列表。类似其他返回结果,此处的列表也用来对表示函数返回的临时量进行初始化。如果列表为空,临时量执行值初始化;否则,返回的值由函数的返回类型决定。

vector<string>process(){    //...    //expected 和 actual是string对象    if(expected.empty())        return {};    else if (expected == actual)        return {"functionX","okay"};    else        return {"functionX",expected,actual};}

如果函数返回的是内置类型,则花括号包围的列表最多包含一个值,而且该值所占空间不应该大于目标类型的空间。如果函数返回的是类类型,有类本身定义初始值如何使用。

返回数组指针

因为数组不能被拷贝,所以函数不能返回数组。不过,函数可以返回数组的指针或引用。

这个比较麻烦,又一个简单的办法~就是使用类型别名

typedef int arrT[10];   //arrT是一个类型别名,它表示的类型是含有10个整数的数组using arrT = int[10];   //arrT的等价声明arrT* func(int i);      //func返回一个指向含有10个整数的数组的指针

如果不用别名,我们来看看怎么办
我们声明指向数组的指针是这样声明的:

int (*p2)[10];

同理我们也这样声明函数

int (*func(int i))[10];

可以按照以下的顺序来逐层理解该声明的含义:

  • func(int i )表示调用func函数时需要一个int类型的实参
  • (*func(int i))意味着我们可以对函数调用的结果执行解引用操作
  • (*func(int i))[10]表示解引用将得到一个大小是10的数组
  • int (*func(int i))[10]表示数组中的元素是int类型