C++: Essential C++ 读书笔记(chapter2):面向过程编程:使用局部静态对象

C++: Essential C++ 读书笔记:面向过程编程:使用局部静态对象.。

背景:先看下面一个案例

vector<int> fibon_seq(int size)
{
    if (size <= 0 || size >= 1024) {
        cout << "Waring: fibon_seq():" << size int
             << "not supported --reseting to 8" << endl;
        size = 8;
    }
    
    vector<int> elems(size);
    for (int ix = 0; ix < size; ++ix) {

        if (ix == 0 || ix ==1)
            elems[ix] = 1;
    
        else elems[ix] = elems[ix-1] + elems[ix-2];
    }
    return elems;
}

针对这个案例,我们从两个 方面讨论

 1:返回值:以 pointer/ reference (传址方式),传值方式返回。

 2:将 elems 定义成局部静态对象。

1:传址 方式返回函数内定义的对象------不可取

除了一个必要的例外(意指 static 对象),函数内定义的对象,只存在于函数执行 期间。

如果将这些所谓的局部对象的地址返回,会导致运行时错误。

因为:函数是暂时位于程序堆栈(内存的一块特殊区域)之上。局部对象就是放在这块区域,当函数执行完毕,这块区域的内容会被弃置,局部对象也不复存在,一般而言,对根本不存在的对象进行寻址操作,是很不好的一个习惯。

上述例子中:

不论我们是以pointer或者reference形式将 elems返回,都是不正确的,因为elems在 fibon_seq()执行 完毕时已不复存在,将一个不存在的对象,如果做寻址操作,是会出现意想不到异常的。

但是:

如果,我们以传值的方式将elems 返回,就不会出现任何问题,因为传值这种方式,它返回的是对象的副本,在函数之外,它仍然存在。 

  1. 对象在程序内的存活区域称为该对象的 scope(作用域)。 我们说 size和 elems在 fibon_seq()执行,都会为elems 分配内存,每当 fibon_seq() 结束便会加以释放。我们称此对象具有局部性范围(local extent),函数参数也具有局部性范围。
  2. 对象如果函数之外声明,具有所谓的 file scope 。对象如果用用 file scope,从其声明点至文件末尾都是可见的。 file scope内的对象也具备 所谓的 static extent (静态存储区)。 意即该对象的内存在 main()开始执行之前便已经分配好,可以一直存在至程序结束。

2:传 址方式可取之处

  1. 当我们以 by reference方式将对象作为函数参数传入时,对象本身不会复制出另一份 ------复制的是对象的地址。所以,在函数中对该对象的任何操作,都相当于是对传入的对象进行间接操作。
  2. 将参数声明为 reference的理由之一是:希望直接对传入的对象进行修改,这个理由极为重要。
  3. 将参数作为 reference的理由之二是:降低复制大型对象的额外负担,这个理由相比起来不那么重要,因为只是堆程序而言不过就是效率问题。

那么by pointer 和by reference的区别是什么了?

1:共同点:都可以直接对传入的对象进行修改

2:不同点:

  • by reference 是引用代表某个对象,一旦代表某个对象,就不能代表其他对象,C++规定,引用代表的对象必须从一而终。 (reference,必定会代表某个对象,在寻址时,不必做检查)
  • by pointer : 是指向某个对象,它可以随时随地指向任何不同对象,也 可以不指向某个实际对象(所以当我们提领某个 pointer时,一定要检查其值是否为0)

3:使用局部静态对象 

在 fibon_seq()函数每次没调用时,会以一个vectror储存计算出来的元素,然后返回,这里话费了一些不必要的功夫。

我们需要的是一个vector,从 fibon_seq()的某次调用到下一次调用,这中间唯一会改变的只是用户指定的元素个数而已,不需要新的每次调用都去构造新vector对象。

显然在函数内部声明局部(local)vector对象并不能解决上述问题,因为局部对象会在每次调用函数时建立,并在函数结束的同时被弃置。

  1. 如果将vector对象定义于 file scope中,又过于冒险,是的。为了节省函数间的通信问题而将对象定义于 file scope内,这永远是一种冒险,通常,file scope对象会打乱不同函数之间的独立性,使他们难以理解
  2. 这个时候 局部静态变量就起作用了,和 局部非静态变量不同的是:局部静态对象所处的内存空间在:静态区,即使在不同函数调用过程中,依然持续存在。elems的内容不再向以前一样地在 fibon_seq()每次被调用时就被破坏后又被重建。这也意味着,我们可以安全的将 elem以 地址的方式返回。

const vector<int>* fibon_seq(int size)
{
    const int max_size = 1024;
    static vector<int> elems;

    if (size <=0 || size > max_size)
    {

        cout<< "fibon_seq(): oops: invialid size: "
             << size << " --cannot fulfill request";
        return 0;
    }

    // 如果size 等于或小于 elems.size(), 就不必重新计算
    for(int ix = elems.size(); ix < size; ix++) {
        if (ix ==0 || ix == 1) {
            elems.push_back(1); 
        } else{
            elems.push_back(elems[ix-1] + elems[ix +2]);
        }
    }
    return &elems;
}

猜你喜欢

转载自blog.csdn.net/u013620306/article/details/128596149
今日推荐