如何在仅标头库中拥有静态数据成员?
-
13-12-2019 - |
题
在不贴上静态图书馆类中静态成员的最佳方法是什么,而不承担定义会员在类用户上的负担?
假设我想提供这个课程:
class i_want_a_static_member
{
static expensive_resource static_resource_;
public:
void foo()
{
static_resource_.bar();
}
};
那么班级的用户绝不能忘记在某个地方定义静态成员(如 回答了 许多 次):
// this must be done somewhere in a translation unit
expensive_resource i_want_a_static_member::static_resource_;
我在下面确实有一个答案,但它有一些缺点。有更好和/或更优雅的解决方案吗?
解决方案
C++17 及以上
使用 inline static
非动态初始化的变量:
struct Foo
{
inline static int I = 0;
};
否则使用函数局部静态变量:
struct Foo
{
static std::string& Bar()
{
static std::string S = compute();
return S;
}
};
C++14 及以下版本
使用函数局部静态,因为它们更容易使用。
如果由于某种原因你真的希望有一个静态的 数据成员, ,那么你可以使用模板技巧:
template <typename T = void>
struct Foo
{
static int I = 0; // inline initialization only for simple types.
};
template <typename T>
int Foo<T>::I;
关于本地静态
对于需要动态初始化的资源,最好使用本地静态。
通常,动态初始化文件范围或类范围静态的顺序是未定义的,当您尝试读取未初始化的静态作为另一个静态的初始化的一部分时,会导致静态初始化顺序失败。本地静态通过在首次使用时延迟初始化来解决该问题。
然而,使用本地静态数据会产生一些轻微的开销。从 C++11 开始,初始化需要是线程安全的,这通常意味着任何访问都由原子读取和良好预测的分支进行门控。
其他提示
我自己的解决方案是使用模板化持有者类,因为静态成员在模板中工作正常,并使用此持有者作为基类。
template <typename T>
struct static_holder
{
static T static_resource_;
};
template <typename T>
T static_holder<T>::static_resource_;
.
现在使用持有者类:
class expensive_resource { /*...*/ };
class i_want_a_static_member : private static_holder<expensive_resource>
{
public:
void foo()
{
static_resource_.bar();
}
};
.
但由于在持有者类中指定了成员的名称,因此您不能使用相同的持有者以获得多个静态成员。
as c ++ 17.您现在可以使用内联变量来执行以下操作:
static const inline float foo = 1.25f;
. 不隶属于 StackOverflow