首先,我将尝试描述当前的情况:
我正在为我们的用途调整现有的代码库,在某些情况下,.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文件时,错误没有再发生。除此之外,我不知道事情是否正常执行。
答案 0 :(得分:1)
正确的方法是将这些定义为static const
,而不是const
。这些是常量,它们不需要静态链接。如果您正在执行此操作以避免全局命名空间,则const
变量无论如何都具有隐式编译单元范围。
答案 1 :(得分:0)
如果从Date::parse_string
构造函数调用Date
并且Date
对象是静态的并且在不同的编译单元(C ++文件)中初始化,那么它可能是与静态变量相关的问题初始化顺序。在这种情况下,未定义变量的初始化顺序,因此Date
对象可能在DATE_FORMAT_REGEX
之前初始化,因此parse_string
在DATE_FORMAT_REGEX
初始化之前被调用。您可以通过将DATE_FORMAT_REGEX
移动到Date
类定义来修复它。
答案 2 :(得分:0)
这很可能是初始化顺序的结果,这是一个众所周知的问题。
很长一段时间以来,已经在书中详细描述了C ++ FAQs。这是一个快速参考:
https://isocpp.org/wiki/faq/ctors#static-init-order
基本上,没有保证静态变量必须初始化的顺序。这会产生一种情况,当“第二个”对象使用“第一个”但是“第一个”尚未初始化时,您可能会遇到错误。请注意,“第一”和“第二”是可以互换的,这就是问题的症结所在。
事实上,更危险的情况是一个潜在的错误,事情继续有效,直到有一天它们没有 - 通常是由新的编译器版本或某些此类变化引起的。
最好完全摆脱这种依赖。你似乎不需要静态。如果目标是限制变量的可见性,则使用匿名命名空间并在任何使用之前放置它。