住房城乡建设部网站办事大厅,安徽省建设安全协会网站,wordpress如何上传html代码,专业做网站的公司哪家更专业在编程过程中,避免使用全局变量是一个良好的编程实践建议。当然,这里的全局变量主要是指 非常量全局变量;
尽管在小型项目中,这一点似乎看起来人畜无害,但是在大型项目中往往会出现很多问题。
新手程序员往往比较喜欢使用大量的全局变量,因为这样使用起来方便直接,特别是当设…在编程过程中,避免使用全局变量是一个良好的编程实践建议。当然,这里的全局变量主要是指 非常量全局变量;
尽管在小型项目中,这一点似乎看起来人畜无害,但是在大型项目中往往会出现很多问题。
新手程序员往往比较喜欢使用大量的全局变量,因为这样使用起来方便直接,特别是当设计到不同函数的多次调用传递参数时。 若无特别说明,本文后续内容中提到的全局变量均指 非常量全局变量。 全局变量的潜在危险
到目前为止,全局变量危险的最大原因是因为他们的值可以在任何地方被任何调用的函数更改,并且程序员没有简单的方法知道这种情况的发生,考虑下面程序:
#include iostreamint g_mode; // 声明全局变量默认会被初始化为0void doSomething()
{g_mode 2; // 将全局变量 g_mode 设置为 2
}int main()
{g_mode 1; // 注意这是将全局变量 g_mode 设置为 1而不是声明一个局部的 g_mode 变量doSomething();// 程序员可能仍然期望 g_mode 的值是 1// 但是 doSomething 函数已经将其更改为 2if (g_mode 1){std::cout 未检测到威胁。\n;}else{std::cout 发射核导弹...\n;}return 0;
}请注意程序员将变量g_mode设置为1 然后调用doSomething() 。除非程序员明确知道doSomething()将更改g_mode的值否则他或她可能不会期望doSomething()更改该值因此 main()的其余部分并不像程序员期望的那样工作,这就导致一枚无情的核弹被发射,恭喜你喜提一份 公牢。
简而言之,全局变量使得程序的状态不可预测,每一个函数调用都具有潜在的危险,并且程序员没有简单的方法来查看和防范这些危险。那么,有什么理由不使用局部变量呢?
除此之外,还有很多其他不推荐使用全局变量的充分理由。
对于全局变量,下面的代码并不罕见:
void someFunction()
{if (g_mode 4){// do something good}
}就短短的几行代码,假设此时你的程序出现错误无法工作,因为全局变量g_mode的值是3而不是4导致。你怎么解决?很好,你首先需要找到名为g_mode的全局变量可能存在的位置并追踪它的赋值等操作,这些工作不仅仅值涉及到你这点代码,很有可能存在于很多毫不相干的代码中!
将局部变量声明为尽可能靠近其使用位置的关键原因之一是这样做可以最大限度地减少您需要查看以了解变量的作用的代码量。
全局变量处于相反的一端——因为它们可以在任何地方访问您可能必须查看整个程序才能了解它们的用法。在小项目中这可能不是问题。但在大项目中,谁说得准呢是吧? 例如,你发现某个全局变量在你的项目中被引用了545次。如果你一开始没有很好的文档跟踪记录,那么你可能必须仔细查看这个变量在每一个地方的使用,以了解它在不同情况下的使用方式、生效条件、影响的逻辑功能等等。 另外,全局变量还会降低程序模块化程度和灵活性 : 当函数依赖全局变量时函数的行为可能受到外部状态的影响无法单独测试或理解其逻辑。 例如函数可能隐式依赖某个全局变量的值而这个值又可能在其他地方被改变导致函数的行为不可预测。 如果函数与全局变量绑定过紧这个函数就无法在其他场景中复用除非那些场景中也包含相同的全局变量。 全局变量的初始化问题
静态变量(包括全局变量)的初始化时程序启动的一部分,在main函数执行之前,这分为两个阶段执行:
第一阶段称为静态初始化。静态初始化分为两个步骤
全局变量带有 constexpr 初始化器包括字面值的会被初始化为这些指定的值这被称为常量初始化。没有初始化器的全局变量会被初始化为零。由于零是一个 constexpr 值因此零初始化也被认为是静态初始化的一种形式。
第二个阶段被称为动态初始化。这一阶段更为复杂和细致但其核心是带有非 constexpr 初始化器的全局变量会在此阶段被初始化。
以下是一个非 constexpr 初始化器的示例
int init()
{return 5;
}int g_something{ init() }; // non-constexpr initialization在单个文件中对于每个阶段全局变量通常按定义顺序进行初始化对于动态初始化阶段此规则有一些例外。鉴于此需要小心不要让变量依赖于稍后才会初始化的其他变量的初始化值。例如
#include iostreamint initX(); // forward declaration
int initY(); // forward declarationint g_x{ initX() }; // g_x is initialized first
int g_y{ initY() };int initX()
{return g_y; // g_y isnt initialized when this is called
}int initY()
{return 5;
}int main()
{std::cout g_x g_y \n;
}更严重的问题是,静态对象在不同翻译单元之间的初始化顺序是不明确的。 给定两个.cpp文件,任意一个文件都可以首先初始化全局变量。如果其中a.cpp中某个具有静态持续时间的变量使用b.cpp中定义的静态持续时间进行变量初始化,则b.cpp中的变量有50%的几率尚未初始化。 使用全局变量的一些建议
首先,在全局变量名加上g_前缀,或者更好的做法是将他们放在命名空间中,以减少出现命名冲突的可能性:
例如,下面的代码;
#include iostreamconstexpr double gravity { 9.8 }; int main()
{std::cout gravity \n; return 0;
}可以调整为:
#include iostreamnamespace constants
{constexpr double gravity { 9.8 };
}int main()
{std::cout constants::gravity \n; are global)return 0;
}其次,一个不错的做法是对变量进行“封装化”,而不是允许直接访问全局变量。
确保变量只能从声明文件内访问,例如将其设置为static或者const,然后提供外部访问函数来处理该变量。这些功能可以确保维护正确的使用,例如进行输入验证、范围检测等。
在编写使用全局变量的独立函数时,不要直接在函数体中使用该变量,相反,我们应该将其作为函数参数传递使用。这样一来,如果你的函数需要在某些情况下使用不同的值,只需要修改参数即可,这也是模块化编程的一种良好实践。
例如:
#include iostreamnamespace constants
{constexpr double gravity { 9.8 };
}double instantVelocity(int time)
{return constants::gravity * time;
}int main()
{std::cout instantVelocity(5) \n;return 0;}建议的写法是:
#include iostreamnamespace constants
{constexpr double gravity { 9.8 };
}double instantVelocity(int time, double gravity)
{return gravity * time;
}int main()
{std::cout instantVelocity(5, constants::gravity) \n; return 0;
}感谢阅读!