我有一个大项目,正在努力进行重构。主要任务是重写记录器。新的记录器(据我所知)与旧的API兼容,因此我相信在更改标头包括目录之后,重新编译并重新链接一切都应该起作用。但不是。我收到多个undefined reference to <static_data_member>
类型的错误。我无法粘贴实际代码,但看起来像这样:
// Foo.h
class Foo {
static const int bar = 0;
int baz; // assigned in c-tor
void updateBaz() { baz = bar; }
// ....
}
static const int bar
在Foo.cpp中未定义。有时它是由日志宏打印的。它曾经可以使用(与旧的记录器一起使用),现在我必须对其进行定义。可能引起什么变化?
另一个由boost声明的变量发生的示例:
(...)/blog_adaptor.h:50: error: undefined reference to bbost::serialization::version<CA::CReyzinSignature>::value'
所以:什么时候需要静态成员的定义?什么时候可以省略它们?
答案 0 :(得分:2)
除非将变量声明为inline
(C ++ 17的一项功能),否则就C ++标准而言,静态成员变量的定义不是可选。无法提供定义是未定义的行为。
编译器和链接器可能会因使检查它们是否存在定义而有所不同,但这就是未定义行为的本质。
答案 1 :(得分:0)
正如Nicol Bolas回答的那样,我的项目中的代码具有未定义的行为,因为静态数据成员已初始化但未定义。总结和扩展: 在以下情况下,无需定义静态数据成员:
此外,以下代码显示了为什么我的错误项目之前没有触发链接器错误。我不知道是不是“滥用毒品”还是“还没有伤害您的不确定行为”:
#include <boost/serialization/version.hpp>
class Klass {};
//BOOST_CLASS_VERSION(Klass, 3);
// would be expanded to:
namespace boost { namespace serialization {
template<>
struct version<Klass> {
static const int value = 3; // not defined anywhere
};
} }
int foo (int val) { // was used by old logger
return val;
}
int bar (const int &val) { // is used by new logger
return val;
}
int main () {
// return bar(boost::serialization::version<Klass>::value); // link error
return foo(boost::serialization::version<Klass>::value); // works fine
}
因此,如果使用成员,则不会出现链接错误,但不会查询其地址。通过引用传递值符合查询地址的条件。