何时需要定义类的静态数据成员 (un/-)

When is definition of class' static data member (un/-)necesary

本文关键字:un 数据成员 静态 定义 何时需      更新时间:2023-10-16

我有一个大项目,正在努力重构它。主要任务是重写记录器。新的记录器(据我所知(与旧记录器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'

那么:什么时候需要静态成员的定义,什么时候可以省略它们?

除非变量被声明为inline(C++17 特征(,否则就C++标准而言,静态成员变量的定义不是可选的。未能提供定义是未定义的行为。

编译器和链接器可能会有所不同,确切地说是什么使它们检查是否存在定义,但这是未定义行为的本质。

正如Nicol Bolas回答的那样,我的项目中的代码具有未定义的行为,因为静态数据成员已初始化,但没有定义。总结和扩展: 在以下情况下不需要定义静态数据成员:

  • 它不使用或仅在丢弃的分支中使用(constexpr-if 的非实例化模板和丢弃的分支(
  • 在 C++17 中,如果成员是内联的
  • Clang-Tidy还说"constexpr静态数据成员的离线定义在C++17中是多余的,并且已被弃用",所以可能静态constexpr也不需要它

此外,以下代码显示了为什么我的错误项目之前没有触发链接器错误。我不知道是"不是odr使用"还是"尚未伤害您的未定义行为":

#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
}

因此,如果使用成员,则没有链接错误,但不查询其地址。通过引用传递值符合查询地址的条件。