简体   繁体   English

C++ 常量的最佳实践

[英]C++ Best practices for constants

I have a whole bunch of constants that I want access to in different parts of my code, but that I want to have easy access to as a whole:我有一大堆常量,我想在代码的不同部分访问它们,但我希望整体上可以轻松访问:

static const bool doX = true;
static const bool doY = false;
static const int maxNumX = 5;

etc.等等。

So I created a file called "constants.h" and stuck them all in there and #included it in any file that needs to know a constant.因此,我创建了一个名为“constants.h”的文件,并将它们全部放入其中,并将其 #included 到任何需要知道常量的文件中。

Problem is, this is terrible for compile times, since every time I change a constant, all files that constants.h reference have to be rebuilt.问题是,这对于编译时间来说很糟糕,因为每次我更改常量时,都必须重新构建 constants.h 引用的所有文件。 (Also, as I understand it, since they're static, I'm generating a copy of doX/doY/maxNumX in code every time I include constants.h in a new .cpp, leading to kilobytes of wasted space in the compiled EXE -- is there any way to see this?). (此外,据我所知,因为它们是静态的,所以每次我在新的 .cpp 中包含 constants.h 时,我都会在代码中生成 doX/doY/maxNumX 的副本,从而导致在已编译的文件中浪费了数千字节的空间EXE——有什么办法可以看到这个吗?)。

So, I want a solution.所以,我想要一个解决方案。 One that isn't "declare constants only in the files that use them", if possible.如果可能的话,一种不是“仅在使用它们的文件中声明常量”。

Any suggestions?有什么建议?

The only alternative is to make your constants extern and define them in another .cpp file, but you'll lose potential for optimization, because the compiler won't know what value they have when compiling each .cpp`.唯一的替代方法是将常量设为extern并在另一个.cpp文件中定义它们,但是您将失去优化的潜力,因为编译器在编译每个 .cpp` 时不知道它们具有什么值。

By the way, don't worry about the size increase: for integral types your constants are likely to be inlined directly in the generated machine code.顺便说一句,不要担心大小增加:对于整数类型,您的常量可能会直接内联在生成的机器代码中。

Finally, that static is not necessary, since by default const global variables are static in C++.最后,该static不是必需的,因为默认情况下, const全局变量在 C++ 中是static

I think your base assumption is off.我认为你的基本假设是错误的。

Your other headers are usually organized by keeping together what works together.您的其他标题通常通过将一起工作的内容放在一起来组织。 For example, a class and its related methods or two classes heavily interlinked.例如,一个类和它的相关方法或两个类密切相关。

Why group all constants in a single header ?为什么将所有常量分组在一个标题中? It does not make sense.它没有任何意义。 It's about as bad an idea as a "global.h" header to include every single dependency easily.这与"global.h"标头一样糟糕,可以轻松包含每个依赖项。

In general, the constants are used in a particular context.通常,常量用于特定上下文。 For example, an enum used as a flag for a particular function:例如,用作特定函数标志的枚举:

class File {
public:
  enum class Mode {
    Read,
    Write,
    Append
  };

  File(std::string const& filename, Mode mode);

  // ...
};

In this case, it is only natural that those constants live in the same header that the class they are bound to (and even within the class).在这种情况下,这些常量很自然地与它们所绑定的类(甚至在类内)位于同一标头中。

The other category of constants are those that just permeate the whole application.另一类常量是那些渗透整个应用程序的常量。 For example:例如:

enum class Direction {
  Up,
  Down,
  Right,
  Left,
  Forward,
  Backward
};

... in a game where you want to express objects' move regarding the direction they are facing. ...在游戏中,您要表达对象相对于它们所面对的方向的移动。

In this case, creating one header file for this specific set of constants is fine.在这种情况下,为这组特定的常量创建一个头文件就可以了。

And if you really are worried about grouping those files together:如果您真的担心将这些文件组合在一起:

constants/
  Direction.hpp
  Sandwich.hpp
  State.hpp

And you will neatly sidestep the issue of recompiling the whole application when you add a constant... though if you need to, do it, you're paying the cost only once, better than a wrong-sided design you'll have to live off with for the rest of your work.当你添加一个常量时,你会巧妙地回避重新编译整个应用程序的问题......尽管如果你需要,这样做,你只需支付一次成本,比你必须的错误设计要好余下的工作。

You declare them as extern in the header and define them in an implementation file.您在头文件中将它们声明为extern并在实现文件中定义它们。

That way, when you want to change their value, you modify the implementation file and no full re-compilation is necessary.这样,当您想要更改它们的值时,您只需修改实现文件,而无需完全重新编译。

The problem in your variant isn't compilation-related, but logic related.您的变体中的问题与编译无关,而是与逻辑有关。 They will not be globals since each translation unit will have its own copy of the variable.它们不会是全局变量,因为每个翻译单元都有自己的变量副本。

EDIT:编辑:

The C++-ish way of doing it would actually wrapping them in a class: C++-ish 的做法实际上将它们包装在一个类中:

//constants.h
class Constants
{
public:
   static const bool doX;
   static const bool doY;
   static const int maxNumX;
}

//constants.cpp
const bool Constants::doX = true;
const bool Constants::doY = false;
const int Constants::maxNumX = 5;

What is the problem with this usage?这种用法有什么问题?
Do not declare a static type in header file, It does not do what you think it does.不要在头文件中声明static类型,它不会做你认为的那样。

When you declare a static in header file a copy of that variable gets created in each Translation Unit(TU) where you include that header file, SO each TU sees a different variable, this is opposite to your expectation of having a global.当您在头文件中声明静态时,会在包含该头文件的每个翻译单元 (TU)中创建该变量的副本,因此每个 TU 都会看到不同的变量,这与您对全局变量的期望相反。

Suggested Solution:建议的解决方案:
You should declare them as extern in a header file and define them in exactly one cpp file while include the header with extern in every cpp file where you want to access them.您应该在头文件中将它们声明为extern并将它们定义在一个 cpp 文件中,同时在要访问它们的每个 cpp 文件中包含带有extern的头文件。

Good Read:好读:
How should i use extern? 我应该如何使用外部?

Another approach which is best for compile times (but has some minor run-time cost) is to make the constants accessible via static methods in a class.另一种最适合编译时间的方法(但有一些小的运行时成本)是使常量可以通过类中的静态方法访问。

//constants.h
class Constants
{
public:
  static bool doX();
  static bool doY();
  static int maxNumX();
};

//constants.cpp
bool Constants::doX() { return true; }
bool Constants::doY() { return false; }
int Constants::maxNumX() { return 42; }

The advantage of this approach is that you only recompile everything if you add/remove/change the declaration of a method in the header, while changing the value returned by any method requires only compiling constants.cpp (and linking, of course).这种方法的优点是,如果您在头文件中添加/删除/更改方法的声明,您只需重新编译所有内容,而更改任何方法返回的值只需要编译 constants.cpp(当然还有链接)。

As with most things, this may or may not be the best is your particular case, but it is another option to consider.与大多数事情一样,根据您的具体情况,这可能是也可能不是最好的,但这是另一个需要考虑的选择。

The straight forward way is, to create non const symbols:直接的方法是创建非 const 符号:

const bool doX = true;
const bool doY = false;
const int maxNumX = 5;

These values will be replaced by the compiler with the given values.这些值将被编译器替换为给定的值。 Thats the most efficient way.那是最有效的方法。 This also of course leads to recompilation as soon as you modify or add values.这当然也会导致在您修改或添加值时立即重新编译。 But in most cases this should not raise practical problems.但在大多数情况下,这不会引起实际问题。

Of course there are different solutions:当然也有不同的解决方案:

  • Using static const s, (or static const class members) the values can be modified without recompilation of all refered files - but thereby the values are held in a const data segment that will be called during runtime rather than being resolved at compile tine.使用static const (或静态常量类成员)可以在不重新编译所有引用文件的情况下修改值 - 但因此这些值保存在常量数据段中,该数据段将在运行时调用,而不是在编译时解析。 If runtime perfomance is no issue (as it is for 90% of most typical code) thats OK.如果运行时性能没有问题(对于 90% 的大多数典型代码都是如此),那没问题。

  • The straight C++ way is using class enums rather than global const identifiers (as noted my Mathieu).直接的 C++ 方法是使用类enums而不是全局常量标识符(如我的 Mathieu 所述)。 This is more typesafe and besides this it works much as const : The symbols will be resolved at compile time.这是更类型安全的,除此之外,它的工作方式与const非常相似:符号将在编译时解析。

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

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