C ++:定义非类静态const值的正确方法是什么?

时间:2015-06-09 15:36:08

标签: c++ static const

首先,我将尝试描述当前的情况:

我正在为我们的用途调整现有的代码库,在某些情况下,.h / .cpp文件包含多个类定义。我们无法在不对代码的其他部分进行重大修改的情况下更改API的现有公共接口。我们现在宁愿避免这些部分。

我发现需要多个类使用的常量值(在同一个.cpp文件中,而不是其他地方),因此不能将其定义为特定于类的常量。我知道这样做的唯一方法是从任何类外部定义常量(但仍然在.cpp文件中)并根据需要引用它们。

我已经完成了这个并且代码编译和链接,但是当我在代码上运行测试程序时,它失败并显示与我定义的常量值相关的错误。我得到的印象是,当代码执行时,实际上没有定义常量,因此代码就会爆炸。

我没有很多编写C ++代码的经验,并且想知道我是否以错误的方式做这件事。我将在下面添加代码段,以试图说明我正在做的事情。

在DateTime.cpp中(当前没有在DateTime.h中为DATE_FORMAT_REGEX定义):

...
#include <boost/regex.hpp>

static const boost::regex DATE_FORMAT_REGEX("[0-9]{4}-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])(Z|([+|-]([01][0-9]|2[0-4]):[0-5][0-9]))?");

// Other class method implementations ...

bool our_ns::Date::parse_string(const std::string& s)
{
  // Validate string against regex.
  bool valid = boost::regex_match(s, DATE_FORMAT_REGEX);

  if (valid) {
    ...
  }
}

...

对regex_match的调用失败了。顺便说一句,所有类都在头文件的名称空间中定义。

看起来常量未被初始化。我需要做些什么来初始化这些值?根据我所描述的内容,有更好的方法吗?

[更新:2015年6月9日12:52美国东部时间] 实际上,我正在转发组织中另一位开发人员目击的信息。他在一个调试器中验证了当regex项目到达它爆炸的行时它是null。他还提到,当他做了一些实验并将定义从.cpp移动到.h文件时,错误没有再发生。除此之外,我不知道事情是否正常执行。

3 个答案:

答案 0 :(得分:1)

正确的方法是将这些定义为static const,而不是const。这些是常量,它们不需要静态链接。如果您正在执行此操作以避免全局命名空间,则const变量无论如何都具有隐式编译单元范围。

答案 1 :(得分:0)

如果从Date::parse_string构造函数调用Date并且Date对象是静态的并且在不同的编译单元(C ++文件)中初始化,那么它可能是与静态变量相关的问题初始化顺序。在这种情况下,未定义变量的初始化顺序,因此Date对象可能在DATE_FORMAT_REGEX之前初始化,因此parse_stringDATE_FORMAT_REGEX初始化之前被调用。您可以通过将DATE_FORMAT_REGEX移动到Date类定义来修复它。

答案 2 :(得分:0)

这很可能是初始化顺序的结果,这是一个众所周知的问题。

很长一段时间以来,已经在书中详细描述了C ++ FAQs。这是一个快速参考:

https://isocpp.org/wiki/faq/ctors#static-init-order

基本上,没有保证静态变量必须初始化的顺序。这会产生一种情况,当“第二个”对象使用“第一个”但是“第一个”尚未初始化时,您可能会遇到错误。请注意,“第一”和“第二”是可以互换的,这就是问题的症结所在。

事实上,更危险的情况是一个潜在的错误,事情继续有效,直到有一天它们没有 - 通常是由新的编译器版本或某些此类变化引起的。

最好完全摆脱这种依赖。你似乎不需要静态。如果目标是限制变量的可见性,则使用匿名命名空间并在任何使用之前放置它。