C++ 全局变量不好吗?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/484635/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Are global variables bad?
提问by Brian Rasmussen
In C/C++, are global variables as bad as my professor thinks they are?
在 C/C++ 中,全局变量有我教授认为的那么糟糕吗?
回答by Brian Rasmussen
The problem with global variables is that since every function has access to these, it becomes increasingly hard to figure out which functions actually read and write these variables.
全局变量的问题在于,由于每个函数都可以访问这些变量,因此越来越难以确定哪些函数实际读写了这些变量。
To understand how the application works, you pretty much have to take into account every function which modifies the global state. That can be done, but as the application grows it will get harder to the point of being virtually impossible (or at least a complete waste of time).
要了解应用程序的工作原理,您几乎必须考虑修改全局状态的每个函数。这是可以做到的,但随着应用程序的增长,它会变得几乎不可能(或至少完全浪费时间)。
If you don't rely on global variables, you can pass state around between different functions as needed. That way you stand a much better chance of understanding what each function does, as you don't need to take the global state into account.
如果您不依赖全局变量,则可以根据需要在不同函数之间传递状态。这样你就更有可能理解每个函数的作用,因为你不需要考虑全局状态。
回答by Tom West
The important thing is to remember the overall goal: clarity
重要的是要记住总体目标:清晰
The "no global variables" rule is there because most of the time, global variables make the meaning of code less clear.
“无全局变量”规则之所以存在,是因为在大多数情况下,全局变量会使代码的含义不太清楚。
However, like many rules, people remember the rule, and not what the rule was intended to do.
然而,像许多规则一样,人们记住的是规则,而不是规则的目的。
I've seen programs that seem to double the size of the code by passing an enormous number of parameters around simply to avoid the evil of global variables. In the end, using globals would have made the program clearerto those reading it. By mindlessly adhering to the word of the rule, the original programmer had failed the intent of the rule.
我见过的程序似乎通过传递大量参数来避免全局变量的邪恶,从而使代码的大小增加一倍。最后,使用全局变量会使阅读它的人更清楚程序。通过盲目地遵守规则的话,最初的程序员没有达到规则的意图。
So, yes, globals are often bad. But if you feel that in the end, the intent of the programmer is made clearer by the use of global variables, then go ahead. However, remember the drop in clarity that automatically ensues when you force someone to access a second piece of code (the globals) to understand how the first piece works.
所以,是的,全局变量通常很糟糕。但是如果你觉得最后通过全局变量的使用让程序员的意图更加清晰,那就继续吧。但是,请记住,当您强迫某人访问第二段代码(全局变量)以了解第一段代码的工作原理时,清晰度会自动下降。
回答by barneytron
My professor used to say something like: using global variables are okay if you use them correctly. I don't think I ever got good at using them correctly, so I rarely used them at all.
我的教授曾经说过这样的话:如果正确使用全局变量,就可以使用它们。我不认为我擅长正确使用它们,所以我很少使用它们。
回答by barneytron
Global variables should only be used when you have no alternative. And yes, that includes Singletons. 90% of the time, global variables are introduced to save the cost of passing around a parameter. And then multithreading/unit testing/maintenance coding happens, and you have a problem.
仅当您别无选择时才应使用全局变量。是的,这包括单身人士。90% 的情况下,引入全局变量是为了节省传递参数的成本。然后多线程/单元测试/维护编码发生,你有问题。
So yes, in 90% of the situations global variables are bad. The exceptions are not likely to be seen by you in your college years. One exception I can think off the top of my head is dealing with inherently global objects such as interrupt tables. Things like DB connection seemto be global, but ain't.
所以是的,在 90% 的情况下,全局变量都是不好的。您在大学期间不太可能看到例外情况。我能想到的一个例外是处理固有的全局对象,例如中断表。像数据库连接这样的事情似乎是全球性的,但不是。
回答by Richard Chambers
The problem that global variables create for the programmer is that it expands the inter-component couplingsurface between the various components that are using the global variables. What this means is that as the number of components using a global variable increases, the complexity of the interactions can also increase. This increased coupling usually makes defects easier to inject into the system when making changes and also makes defects harder to diagnose and correct. This increase coupling can also reduce the number of available options when making changes and it can increase the effort required for changes as often one must trace through the various modules that are also using the global variable in order to determine the consequences of changes.
全局变量为程序员创建的问题是它扩展了使用全局变量的各种组件之间的组件间耦合面。这意味着随着使用全局变量的组件数量的增加,交互的复杂性也会增加。这种增加的耦合通常会使在进行更改时更容易将缺陷注入系统,也使缺陷更难以诊断和纠正。这种增加的耦合还可以减少进行更改时可用选项的数量,并且可以增加更改所需的工作量,因为通常必须跟踪也使用全局变量的各种模块,以确定更改的后果。
The purpose of encapsulation, which is basically the opposite of using global variables, is to decrease coupling in order to make understanding and changing the source easier and safer and more easily tested. It is much easier to use unit testingwhen global variables are not used.
封装的目的,基本上与使用全局变量相反,是为了减少耦合,使理解和更改源更容易、更安全、更容易测试。当不使用全局变量时,使用单元测试要容易得多。
For example if you have a simple global integer variable that is being used as an enumerated indicator that various components use as a state machine and you then make a change by adding a new state for a new component, you must then trace through all the other components to ensure that the change will not affect them. An example of a possible problem would be if a switch
statement to test the value of the enumeration global variable with case
statements for each of the current values is being used in various places and it so happens that some of the switch
statements do not have a default
case to handle an unexpected value for the global all of a sudden you have undefined behavior so far as the application is concerned.
例如,如果您有一个简单的全局整数变量,它被用作各种组件用作状态机的枚举指示器,然后您通过为新组件添加新状态来进行更改,那么您必须跟踪所有其他组件组件以确保更改不会影响它们。一个可能的问题的例子是,如果在不同的地方使用了用每个当前值的switch
语句来测试枚举全局变量的值的case
语句,并且碰巧某些switch
语句没有default
要处理的情况一个意外的全局值突然之间就应用程序而言,您有未定义的行为。
On the other hand the use of a shared data area might be used to contain a set of global parameters which are referenced throughout the application. This approach is often used with embedded applications with small memory footprints.
另一方面,共享数据区的使用可能用于包含在整个应用程序中引用的一组全局参数。这种方法通常用于内存占用较小的嵌入式应用程序。
When using global variables in these sort of applications typically the responsibility for writing to the data area is allocated to a single component and all other components see the area as const
and read from it, never writing to it. Taking this approach limits the problems that can develop.
在这类应用程序中使用全局变量时,写入数据区的责任通常被分配给单个组件,所有其他组件都将该区域视为const
并从中读取,从不写入。采用这种方法可以限制可能出现的问题。
A few problems from global variables which need to be worked around
需要解决的全局变量的一些问题
When the source for a global variable such as a struct is modified, everything using it must be recompiled so that everything using the variable knows its true size and memory template.
当一个全局变量(如结构体)的源被修改时,所有使用它的东西都必须重新编译,这样所有使用该变量的东西都知道它的真实大小和内存模板。
If more than one component can modify the global variable you can run into problems with inconsistent data being in the global variable. With a multi-threading application, you will probably need to add some kind of locking or critical region to provide a way so that only one thread at a time can modify the global variable and when a thread is modifying the variable, all changes are complete and committed before other threads can query the variable or modify it.
如果多个组件可以修改全局变量,您可能会遇到全局变量中数据不一致的问题。对于多线程应用程序,您可能需要添加某种锁定或临界区来提供一种方法,以便一次只有一个线程可以修改全局变量,并且当一个线程正在修改该变量时,所有更改都已完成并在其他线程可以查询或修改变量之前提交。
Debugging a multi-threaded application that uses a global variable can be more difficult. You can run into race conditionsthat can create defects that are difficult to replicate. With several components communicating through a global variable, especially in a multi-threaded application, being able to know what component is changing the variable when and how it is changing the variable can be very difficult to understand.
调试使用全局变量的多线程应用程序可能更加困难。您可能会遇到竞争条件,从而产生难以复制的缺陷。由于多个组件通过全局变量进行通信,尤其是在多线程应用程序中,因此很难了解哪个组件在何时以及如何更改变量。
Name clash can be a problem with using of global variables. A local variable that has the same name as a global variable can hide the global variable. You also run into the naming convention issue when using the C programming language. A work around is to divide the system up into sub-systems with the global variables for a particular sub-system all beginning with the same first three letters (see this on resolving name space collisions in objective C). C++ provides namespaces and with C you can work around this by creating a globally visible struct whose members are various data items and pointers to data and functions which are provided in a file as static hence with file visibility only so that they can only be referenced through the globally visible struct.
名称冲突可能是使用全局变量的问题。与全局变量同名的局部变量可以隐藏全局变量。在使用 C 编程语言时,您还会遇到命名约定问题。一种变通方法是将系统分成多个子系统,其中特定子系统的全局变量都以相同的前三个字母开头(请参阅有关解决目标 C 中的名称空间冲突的内容)。C++ 提供了命名空间,使用 C,您可以通过创建一个全局可见的结构来解决这个问题,该结构的成员是各种数据项以及指向数据和函数的指针,这些数据和函数在文件中作为静态提供,因此只有文件可见性,因此它们只能通过全局可见的结构。
In some cases the original application intent is changed so that global variables that provided the state for a single thread is modified to allow several duplicate threads to run. An example would be a simple application designed for a single user using global variables for state and then a request comes down from management to add a REST interfaceto allow remote applications to act as virtual users. So now you run into having to duplicate the global variables and their state information so that the single user as well as each of the virtual users from remote applications have their own, unique set of global variables.
在某些情况下,原始应用程序意图被更改,以便为单个线程提供状态的全局变量被修改以允许多个重复线程运行。一个示例是为单个用户设计的简单应用程序,使用全局变量作为状态,然后来自管理层的请求添加REST 接口以允许远程应用程序充当虚拟用户。因此,现在您不得不复制全局变量及其状态信息,以便单个用户以及来自远程应用程序的每个虚拟用户都有自己独特的全局变量集。
Using C++ namespace
and the struct
Technique for C
使用 C++namespace
和struct
C 技术
For the C++ programming language the namespace
directive is a huge help in reducing the chances of a name clash. namespace
along with class
and the various access keywords (private
, protected
, and public
) provide most of the tools you need to encapsulate variables. However the C programming language doesn't provide this directive. This stackoverflow posting, Namespaces in C, provides some techniques for C.
对于 C++ 编程语言,该namespace
指令在减少名称冲突的可能性方面有很大帮助。namespace
以及class
各种访问关键字(private
、protected
、 和public
)提供了封装变量所需的大多数工具。但是,C 编程语言不提供此指令。这个 stackoverflow 发布,C中的命名空间,为 C提供了一些技术。
A useful technique is to have a single memory resident data area that is defined as a struct
which has global visibility and within this struct
are pointers to the various global variables and functions that are being exposed. The actual definitions of the global variables are given file scope using the static
keyword. If you then use the const
keyword to indicate which are read only, the compiler can help you to enforce read only access.
一个有用的技术是拥有一个定义为struct
具有全局可见性的单个内存驻留数据区域,其中包含struct
指向正在公开的各种全局变量和函数的指针。全局变量的实际定义是使用static
关键字指定的文件范围。如果您然后使用const
关键字来指示哪些是只读的,编译器可以帮助您强制执行只读访问。
Using the struct
technique can also encapsulate the global so that it becomes a kind of package or component that happens to be a global. By having a component of this kind it becomes easier to manage changes that affect the global and the functionality using the global.
使用该struct
技术还可以封装全局,使其成为一种恰好是全局的包或组件。通过拥有此类组件,可以更轻松地管理影响全局和使用全局的功能的更改。
However while namespace
or the struct
technique can help manage name clashes, the underlying problems of inter-component coupling which the use of globals introduces especially in a modern multi-threaded application, still exist.
然而,尽管namespace
该struct
技术可以帮助管理名称冲突,但使用全局变量引入的组件间耦合的潜在问题仍然存在,尤其是在现代多线程应用程序中。
回答by user54650
Global variables are as bad as you make them, no less.
全局变量和你创造的一样糟糕,同样如此。
If you are creating a fully encapsulated program, you can use globals. It's a "sin" to use globals, but programming sins are laregly philosophical.
如果您正在创建一个完全封装的程序,您可以使用全局变量。使用全局变量是一种“罪”,但编程的罪是极少哲学上的。
If you check out L.in.oleum, you will see a language whose variables are solely global. It's unscalable because libraries all have no choice but to use globals.
如果您查看L.in.oleum,您将看到一种变量完全是全局的语言。这是不可扩展的,因为库都别无选择,只能使用全局变量。
That said, if you have choices, and can ignore programmer philosophy, globals aren't all that bad.
也就是说,如果您有选择,并且可以忽略程序员的哲学,那么全局变量并不是那么糟糕。
Neither are Gotos, if you use them right.
如果您使用得当,Goto 也不是。
The big "bad" problem is that, if you use them wrong, people scream, the mars lander crashes, and the world blows up....or something like that.
最大的“坏”问题是,如果你错误地使用它们,人们会尖叫,火星着陆器坠毁,世界会爆炸......或类似的事情。
回答by MSN
Yes, but you don't incur the cost of global variables until you stop working in the code that uses global variables and start writing something else that uses the code that uses global variables. But the cost is still there.
是的,但是直到您停止在使用全局变量的代码中工作并开始编写使用使用全局变量的代码的其他内容之前,您不会产生全局变量的成本。但成本仍然存在。
In other words, it's a long term indirect cost and as such most people think it's not bad.
换句话说,这是一个长期的间接成本,因此大多数人认为这还不错。
回答by Casey
If it's possible your code will end up under intensive reviewduring a Supreme Court trial, then you want to make sure to avoid global variables.
如果您的代码最终可能会在最高法院审判期间接受密集,那么您要确保避免使用全局变量。
See this article: Buggy breathalyzer code reflects importance of source review
请参阅这篇文章:错误的呼气测醉器代码反映了源代码的重要性
There were some problems with the style of the code that were identified by both studies. One of the stylistic issues that concerned the reviewers was the extensive use of unprotected global variables. This is considered poor form because it increases the risk that the program state will become inconsistent or that values will be inadvertently modified or overwritten. The researchers also expressed some concern about the fact that decimal precision is not maintained consistently throughout the code.
两项研究都发现代码风格存在一些问题。审阅者关注的文体问题之一是未受保护的全局变量的广泛使用。这被认为是糟糕的形式,因为它增加了程序状态变得不一致或值被无意修改或覆盖的风险。研究人员还对整个代码中未始终保持小数精度的事实表示担忧。
Man, I bet those developers are wishing they hadn't used global variables!
伙计,我敢打赌那些开发人员希望他们没有使用全局变量!
回答by Gavin Miller
I'd answer this question with another question: Do you use singeltons/ Are singeltons bad?
我会用另一个问题来回答这个问题:你使用单胞胎吗/单胞胎不好吗?
Because (almost all) singelton usage is a glorified global variable.
因为(几乎所有)单例用法是一个美化的全局变量。
回答by Justin Time - Reinstate Monica
The issue is less that they're bad, and more that they're dangerous. They have their own set of pros and cons, and there are situations where they're either the most efficient or only way to achieve a particular task. However, they're veryeasy to misuse, even if you take steps to always use them properly.
问题不是它们不好,而是它们很危险。它们有自己的优点和缺点,在某些情况下,它们要么是完成特定任务的最有效方法,要么是唯一的方法。但是,它们很容易被误用,即使您采取措施始终正确使用它们。
A few pros:
几个优点:
- Can be accessed from any function.
- Can be accessed from multiple threads.
- Will never go out of scope until the program ends.
- 可以从任何函数访问。
- 可以从多个线程访问。
- 在程序结束之前永远不会超出范围。
A few cons:
一些缺点:
- Can be accessed from any function, without needing to be explicitly dragged in as a parameter and/or documented.
- Not thread-safe.
- Pollutes the global namespace and potentially causes name collisions, unless measures are taken to prevent this.
- 可以从任何函数访问,无需作为参数显式拖入和/或记录。
- 不是线程安全的。
- 污染全局命名空间并可能导致名称冲突,除非采取措施防止这种情况发生。
Note, if you will, that the first two pros and the first two cons I listed are the exact same thing, just with different wording. This is because the features of a global variable can indeed be useful, but the very features that make them useful are the source of all their problems.
请注意,如果您愿意,我列出的前两个优点和前两个缺点是完全相同的,只是措辞不同。这是因为全局变量的特性确实很有用,但正是使它们有用的特性才是它们所有问题的根源。
A few potential solutions to some of the problems:
一些问题的一些潜在解决方案:
- Consider whether they're actually the best or most efficient solution for the problem. If there are anybetter solutions, use that instead.
- Put them in a namespace [C++] or singleton struct [C, C++] with a unique name (a good example would be
Globals
orGlobalVars
), or use a standardised naming convention for global variables (such asglobal_[name]
org_module_varNameStyle
(as mentioned by underscore_d in the comments)). This will both document their use (you can find code that uses global variables by searching for the namespace/struct name), and minimise the impact on the global namespace. - For any function that accesses global variables, explicitly document which variables it reads and which it writes. This will make troubleshooting easier.
- Put them in their own source file and declare them
extern
in the associated header, so their use can be limited to compilation units that need to access them. If your code relies on a lot of global variables, but each compilation unit only needs access to a handful of them, you could consider sorting them into multiple source files, so it's easier to limit each file's access to global variables. - Set up a mechanism to lock and unlock them, and/or design your code so that as few functions as possible need to actually modifyglobal variables. Reading them is a lot safer than writing them, although thread races may still cause problems in multithreaded programs.
- Basically, minimise access to them, and maximise name uniqueness. You want to avoid name collisions and have as few functions as possible that can potentially modify any given variable.
- 考虑它们是否实际上是解决问题的最佳或最有效的解决方案。如果有任何更好的解决方案,使用来代替。
- 将它们放在命名空间 [C++] 或具有唯一名称的单例结构 [C, C++] 中(一个很好的例子是
Globals
orGlobalVars
),或使用全局变量的标准化命名约定(例如global_[name]
org_module_varNameStyle
(如注释中的 underscore_d 所述) ))。这将记录它们的使用(您可以通过搜索命名空间/结构名称找到使用全局变量的代码),并最大限度地减少对全局命名空间的影响。 - 对于访问全局变量的任何函数,明确记录它读取和写入的变量。这将使故障排除更容易。
- 将它们放在自己的源文件中,并
extern
在关联的头文件中声明它们,因此它们的使用可以仅限于需要访问它们的编译单元。如果你的代码依赖大量的全局变量,而每个编译单元只需要访问其中的几个,你可以考虑将它们整理成多个源文件,这样更容易限制每个文件对全局变量的访问。 - 设置一种机制来锁定和解锁它们,和/或设计您的代码,以便尽可能少的函数需要实际修改全局变量。阅读它们比编写它们安全得多,尽管线程竞争仍然可能在多线程程序中引起问题。
- 基本上,尽量减少对它们的访问,并最大限度地提高名称的唯一性。您希望避免名称冲突并尽可能少地使用可能修改任何给定变量的函数。
Whether they're good or bad depends on how you use them. The majority tend to use them badly, hence the general wariness towards them. If used properly, they can be a major boon; if used poorly, however, they can and willcome back to bite you when and how you least expect it.
它们的好坏取决于您如何使用它们。大多数人倾向于错误地使用它们,因此对它们普遍持谨慎态度。如果使用得当,它们可以成为一大福音;但是,如果使用不当,它们会并且会在您最不期望的时候以何种方式咬您。
A good way to look at it is that they themselves aren't bad, but they enable bad design, and can multiply the effects of bad design exponentially.
看待它的一个好方法是它们本身并不坏,但它们会导致糟糕的设计,并且可以成倍地增加糟糕设计的影响。
Even if you don't intend to use them, it is better to know how to use them safely and choose not to, than not to use them because you don't know how to use them safely. If you ever find yourself in a situation where you need to maintain pre-existing code that relies on global variables, you may be in for difficulty if you don't know how to use them properly.
即使您不打算使用它们,也最好知道如何安全地使用它们并选择不使用它们,而不是因为您不知道如何安全地使用它们而不使用它们。如果您发现自己需要维护依赖于全局变量的预先存在的代码,如果您不知道如何正确使用它们,您可能会遇到困难。