基础的知识最容易被轻视,通常被粗浅的理解,最终导致严重的问题。结果轻则耗费大量的精力排查bug,如若设计的代码隐藏了许多不可预测的问题,那么重则将导致系统崩溃、产品功能出错
作用域问题
小情绪:
手头上的一个小任务,设计思路花了不到1小时,编码也没消耗什么成本。但问题排查却消耗了将近两个工作日。从逻辑排查到单元测试,一再反复推敲,甚至怀疑基本的底层运算,在无用的地方耗费精力。每每遇到调试报错显眼的红色,情绪上的焦躁便多上一分。最终在穷举遍历的巨量消耗下,发现自己早已失落在粗浅随性理解构建起的迷宫里,一遍一遍的重复着。
基本概念
作用域: 在程序设计中,为了避免名字冲突,在某一段代码范围中限定了名字所代表变量的作用范围(scope)。
简单至极的一个概念,而在实际应用当中却衍生出不同的用法,如果不能禅透其实质,就容易犯错误。
函数形参的作用域
//Failed
int Swap(int a, int b)
{
int tem;
tem = a;
a = b;
b = tem;
}
//Pointer
int Swap(int *a, int *b)
{
int tem;
tem = *a;
*a = *b;
*b = tem;
}
在检测函数形参作用域时,最能揭示其实质的就是上面的两个例子。交换两个变量的内容,现在回过头来,一眼就能看出问题出在哪了。在函数体执行过程中,首先将传入的实参拷贝给形参,由此函数体内部表面上涉及实参的操作本质上都是克隆对象的独舞,而最后如果不做相应结果的处理,那么在函数体限定的作用域结束之后,所有的形参都将烟消云散。第二个例子,本质是对实参存储地址上的实际内容进行处理,结果自然不会错。
自以为掌握了这一基本概念。在实际应用中,形参换了一个马甲,就认不出来了。单纯的以为只要函数中传的是指针就放之四海解皆准了。看例子:
void Get_pointer(def_type *m_para)
{
// type_1
def_type tem_para = nullptr;
tem_para = function(); //get the useful ptr
m_para = tem_para;
// type_2
m_para = function()
}
例子中,本质是希望获得想要的指针变量,同类型1和类型2得到的结果都是错误的。程序设计者的意图忽视了,指针变量本身就是变量的这一属性。意味着在函数执行过程中页经历了指针变量形参拷贝实参的这一过程,函数体内部的m_para已不在是原来的。