C ++常量的最佳实践

时间:2012-03-10 19:17:19

标签: c++ constants

我有一大堆常量,我想在我的代码的不同部分访问,但我希望能够轻松访问整个:

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

等。

所以我创建了一个名为“constants.h”的文件,并将它们全部放在那里,并将#included包含在任何需要知道常量的文件中。

问题是,这对于编译时来说很糟糕,因为每次更改常量时,都必须重建constants.h引用的所有文件。 (另外,据我所知,因为它们是静态的,所以每次在新的.cpp中包含constants.h时,我都会在代码中生成doX / doY / maxNumX的副本,导致编译中浪费的空间为千字节EXE - 有没有办法看到这个?)。

所以,我想要一个解决方案。一个不是“仅在使用它们的文件中声明常量”,如果可能的话。

有什么建议吗?

6 个答案:

答案 0 :(得分:9)

唯一的选择是制作常量extern并在另一个.cpp文件中定义它们,但是你将失去优化的可能性,因为编译器在编译时不知道它们具有什么值每个.cpp`。

顺便说一下,不要担心大小增加:对于整数类型,你的常量很可能直接在生成的机器代码中内联。

最后,static不是必需的,因为默认情况下const全局变量在C ++中为static

答案 1 :(得分:8)

我认为你的基本假设是关闭的。

您的其他标题通常是通过将哪些标题组合在一起来组织的。例如,一个类及其相关的方法或两个类严重相互关联。

为什么要将所有常量分组到一个标题中?它没有任何意义。与"global.h"标题一样,它很容易包含每一个依赖关系。

通常,常量用于特定上下文中。例如,枚举用作特定函数的标志:

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

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

  // ...
};

在这种情况下,这些常量与它们绑定的类(甚至在类中)所在的标题相同,这是很自然的。

另一类常量是那些只渗透整个应用程序的常量。例如:

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

...在一个游戏中你想要表达物体对他们所面对方向的移动。

在这种情况下,为这组特定的常量创建一个头文件很好。

如果你真的担心将这些文件分组在一起:

constants/
  Direction.hpp
  Sandwich.hpp
  State.hpp

当你添加一个常量时,你会巧妙地回避重新编译整个应用程序的问题......但如果你需要,那么,你只付出一次成本,比你的错误设计更好“我将不得不为你的其余工作而活下去。

答案 2 :(得分:7)

您在标头中将它们声明为extern,并在实现文件中定义它们。

这样,当您想要更改它们的值时,您需要修改实现文件,并且不需要完全重新编译。

您的变体中的问题不是与编译相关的,而是与逻辑相关的。它们不是全局变量,因为每个翻译单元都有自己的变量副本。

编辑:

C ++ - 这样做的方式实际上将它们包装在一个类中:

//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;

答案 3 :(得分:3)

这种用法有什么问题?
不要在头文件中声明static类型,它不会按照您的想法执行。

当您在头文件中声明静态时,会在每个包含该头文件的 Translation Unit(TU) 中创建该变量的副本,因此每个TU看到一个不同的变量,这是相反的你对全球化的期望。

建议的解决方案:
您应该在头文件中将它们声明为extern,并在一个cpp文件中定义它们,同时在每个要访问它们的cpp文件中包含带extern的标头。

好读:
How should i use extern?

答案 4 :(得分:3)

另一种最适合编译时间(但运行时成本较低)的方法是通过类中的静态方法访问常量。

//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; }

这种方法的优点是,只有在标题中添加/删除/更改方法声明时才重新编译所有内容,而更改任何方法返回的值只需要编译constants.cpp(当然还有链接) )。

与大多数情况一样,这可能是您的具体情况,也可能不是最佳情况,但这是另一种选择。

答案 5 :(得分:0)

直接的方法是,创建非常量符号:

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

这些值将由具有给定值的编译器替换。这是最有效的方式。当然,这也会在您修改或添加值时立即重新编译。但在大多数情况下,这不应该引发实际问题。

当然有不同的解决方案:

  • 使用static const s(或静态const类成员)可以修改这些值而无需重新编译所有引用的文件 - 但是这些值保存在将在运行时调用的const数据段中而不是在编译时解决。如果运行时性能没有问题(因为90%的大多数典型代码都没有问题),那就没问题。

  • 直接的C ++方式是使用类enums而不是全局const标识符(如我所说的Mathieu)。这更加类型安全,除此之外它的作用与const相同:符号将在编译时解析。