简体   繁体   English

在C ++中适当使用全局const变量?

[英]Appropriate use of global const variables in C++?

I am working on a program for my CS class. 我正在为我的CS课程开发一个程序。 It is a simulation of a delivery company's activities at an airport. 它模拟了送货公司在机场的活动。

This is a very simple, small program consisting of a few header and source files and a main.cpp source file that orchestrates the simulation. 这是一个非常简单的小程序,由一些头文件和源文件以及一个编排模拟的main.cpp源文件组成。

There are certain given constant values, such as the frequency of shipment arrival, the load capacity of planes, the amount of time it takes a worker to process certain items, etc. (all are integer values). 存在某些给定的常数值,例如装运到达的频率,飞机的负载能力,工人处理某些物品所花费的时间等等(均为整数值)。 It is necessary for me to access these variables throughout several functions in main.cpp 我需要在main.cpp中的几个函数中访问这些变量

It seemed reasonable to declare these above the main() function as const ints, effectively making them global, eg 将main()函数上面的这些声明为const int是合理的,有效地使它们成为全局的,例如

const int kTotalTime = 2000;
const int kPlaneCapacity = 25;
int main(){//...program code}

I am aware that global variables are to be avoided in most situations, as there are no restrictions on where they can be called and/or modified, which can lead to accidentally breaking parts of the program which in turn may be difficult to debug, as well as causing compatibility issues for future code, etc. However since these are read-only values of a primitive data type, which are used throughout the program, it seemed like a reasonable solution. 我知道在大多数情况下都要避免使用全局变量,因为对它们的调用和/或修改位置没有限制,这可能导致意外破坏程序的某些部分,这反过来可能很难调试,如以及为将来的代码等引起兼容性问题。然而,由于这些是在整个程序中使用的原始数据类型的只读值,因此它似乎是一种合理的解决方案。 Also, it makes an explicit statement about the purpose of the variables to anyone reading the code as well as to the compiler. 此外,它向读取代码的任何人以及编译器明确声明了变量的用途。

Questions: Is my logic flawed? 问题:我的逻辑有缺陷吗? How so? 怎么会这样? When are global variables (const or not) reasonable to use? 全局变量(常量或非常量)何时合理使用? If this is a bad solution, then how would you suggest declaring constant read-only values such as these? 如果这是一个糟糕的解决方案,那么您如何建议声明这些常量只读值?

Thank you very much for your time! 非常感谢您的宝贵时间!

I think it's best to put your constants as static inside the class. 我认为最好将常量作为静态放在类中。

I assume you have the class Plane , just do this: 我假设你有类Plane ,就这样做:

Plane.h Plane.h

class Plane{
   static const int kPlaneCapacity;
   //....
}

Plane.cpp Plane.cpp

const int Plane::kPlaneCapacity = 25;

Also, take good care of what you understand by constant. 另外,要注意不断理解你的理解。 Pi is a constant. Pi是一个常数。 10 is a constant. 10是常数。 I do see how you would think a plane capacity is constant, but think about this: What if your teacher says that for your next assignment, your plane capacity should be 30, and not 25. 我确实看到你如何认为飞机的容量是恒定的,但想一想:如果你的老师说你的下一个任务,你的飞机容量应该是30,而不是25。

Regarding the size and purpose of your program (as I understand it from your description) it probably doesn't matter, but since it has an educational context, I'd suggest to " do it right ". 关于你的程序的大小和目的(我从你的描述中理解)它可能无关紧要,但由于它具有教育背景,我建议“ 做正确 ”。

In such a situation I would go for a Config struct (or class, if you want to make it a bit smarter, see below) which carries the configuration values and can be tossed around your program. 在这种情况下,我会选择一个Config结构(或类,如果你想让它更聪明,见下文),它带有配置值并且可以在程序周围抛出。 It has the advantage that you can easily change it if you have to, say, fetch your options from a file or from the command line. 它的优点是,如果您必须从文件或命令行中获取选项,则可以轻松更改它。

As for the class versus struct thingy (note that I am making a logical distinction here, not a technical). 至于类与结构的东西(注意我在这里做出逻辑上的区分,而不是技术上的)。 Either you just put all values as members in your struct and pass around const refs of it, or you make it a full fledged class with accessors that hide where the data is coming from (and how it is generated). 您可以将所有值作为成员放在结构中并传递给它的const引用,或者使它成为一个完整的类,其中包含隐藏数据来源(及其生成方式)的访问器。 Programming is always decision making and this is your decision to make. 编程始终是决策,这是您的决定。 If you think you will have to allow more configuration possibilities in the future (like mentioned above) you may want to go for class abstraction. 如果您认为将来必须允许更多的配置(如上所述),您可能想要进行类抽象。

Yet another option is to scatter your data across your program, which is actually a lot smarter than it sounds. 另一种选择是将数据分散到您的程序中,这实际上比听起来要聪明得多。 If every class knows only its configuration options (and hides them) you can actually make use of the OOP language, you're using. 如果每个类只知道它的配置选项(并隐藏它们),你实际上可以使用你正在使用的OOP语言。 Example: 例:

// footype.h
class FooType {
  private:
    static const int fooOption;
};
// bartype.h
class BarType {
  private:
    static const float barOption;
};

The question is, how to initialise this. 问题是,如何初始化这个。 One way could be to create a config.cpp that looks like this: 一种方法是创建一个如下所示的config.cpp

#include "footype.h"
#include "bartype.h"

const int FooType::fooOption = 42;
const float BarType::barOption = 7.4;

So you have information hiding, and you still have all the config options together at one place ( config.cpp ). 所以你有信息隐藏,你仍然在一个地方( config.cpp )一起拥有所有的配置选项。

Edit: 编辑:

If you have config option that is required by many (more than one) different modules, you can go for a bit of sophistication (with indirection) like so: 如果您有许多(多个)不同模块所需的配置选项,您可以进行一些复杂化(使用间接),如下所示:

// footype.h
class FooType {
  private:
    static const int& fooOption;
    static const bool& dumpLevel;
};
// bartype.h
class BarType {
  private:
    static const float& barOption;
    static const bool& dumpLevel;
};

config.cpp: config.cpp:

#include "footype.h"
#include "bartype.h"

static const int opt_foo = 42;
static const float opt_bar = 7.4;
static const bool opt_dumpLevel = false;

const int& FooType::fooOption = opt_foo;
const bool& FooType::dumpLevel = opt_dumpLevel;
const float& BarType::barOption = opt_bar;
const bool& BarType::dumpLevel = opt_dumpLevel;

You can even make the options non-const if you want (but I don't see the point in a configuration option that is mutable). 如果需要,您甚至可以将选项设置为非const(但我没有看到配置选项中可变的点)。

When are global variables (const or not) reasonable to use? 全局变量(常量或非常量)何时合理使用?

If your program is a multithreaded program then you should be giving a serious thought about using globals for they would need proper synchronization to avoid race conditions . 如果您的程序是多线程程序,那么您应该认真考虑使用全局变量,因为它们需要适当的同步以避免竞争条件 Usually proper synchronization is not a very trivial task and requires some serious undrestanding and thought. 通常,正确的同步不是一项非常简单的任务,需要一些严肃的不受欢迎和思考。

Here is an excerpt from a nice article : 这是一篇好文章的摘录:

Non-locality -- Source code is easiest to understand when the scope of its individual elements are limited. 非本地化 - 当各个元素的范围有限时,源代码最容易理解。 Global variables can be read or modified by any part of the program, making it difficult to remember or reason about every possible use. 全局变量可以由程序的任何部分读取或修改,使得难以记住或推理每种可能的用途。 No Access Control or Constraint Checking -- A global variable can be get or set by any part of the program, and any rules regarding its use can be easily broken or forgotten. 无访问控制或约束检查 - 程序的任何部分都可以获取或设置全局变量,并且可以轻松地删除或忘记有关其使用的任何规则。

Implicit coupling -- A program with many global variables often has tight couplings between some of those variables, and couplings between variables and functions. 隐式耦合 - 具有许多全局变量的程序通常在这些变量之间存在紧密耦合,以及变量和函数之间的耦合。 Grouping coupled items into cohesive units usually leads to better programs. 将耦合项目分组为有凝聚力的单元通常会带来更好的计划。

Memory allocation issues -- Some environments have memory allocation schemes that make allocation of globals tricky. 内存分配问题 - 某些环境具有内存分配方案,使得全局变量分配变得棘手。 This is especially true in languages where "constructors" have side-effects other than allocation (because, in that case, you can express unsafe situations where two globals mutually depend on one another). 在“构造函数”具有除分配之外的副作用的语言中尤其如此(因为,在这种情况下,您可以表示两个全局变量彼此相互依赖的不安全情况)。 Also, when dynamically linking modules, it can be unclear whether different libraries have their own instances of globals or whether the globals are shared. 此外,当动态链接模块时,可能不清楚不同的库是否有自己的全局变量实例或者是否共享全局变量。

Testing and Confinement - source that utilizes globals is somewhat more difficult to test because one cannot readily set up a 'clean' environment between runs. 测试和限制 - 使用全局变量的源更难以测试,因为在运行之间无法轻易建立“干净”的环境。 More generally, source that utilizes global services of any sort that aren't explicitly provided to that source is difficult to test for the same reason. 更一般地,利用未明确提供给该源的任何类型的全局服务的源很难以相同的原因进行测试。

Given all the above, As long as you understand the pitfalls and understand that the way you are using the globals does insulate your program against those pitfalls, then you can go ahead and very well use globals. 鉴于以上所有,只要您了解陷阱并了解使用全局变量的方式确实可以使您的程序与这些陷阱绝缘,那么您可以继续使用全局变量。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM