提问人:Jeremy Friesner 提问时间:8/13/2023 最后编辑:Jeremy Friesner 更新时间:8/13/2023 访问量:37
如何对模板化的只读单例函数进行强制求值?
How to force eager-evaluation of templated read-only singleton function?
问:
我的代码库包含这个非常简单的模板化函数,可以从很多不同的地方调用:
// Returns a read-only reference to a default-constructed
// object of the specified type
template <typename T> const T & GetDefaultObjectForType()
{
static const T _defaultObject{};
return _defaultObject;
}
此函数在模板化代码中很有用,因为它允许模板化代码访问其模板化的类型的默认构造对象,而不必为此目的构造一个对象。
它运行良好,但我今天遇到的问题是 helgrind 告诉我,当我有多个线程调用此函数时,存在争用条件;这是因为 G++ 的函数底层实现看起来更像是这样(伪代码):
template <typename T> const T & GetDefaultObjectForType()
{
static char _defaultObject[sizeof(T)];
static std::atomic<bool> _isConstructed = false;
if (_isConstructed == false)
{
_isConstructed = true;
new (_defaultObject) T(); // demand-construct the object!
}
return reinterpret_cast<const T &>(_defaultObject);
}
...因此,由于上述原因,告诉我线程 A 的调用 to 已写入对象(即 demand-construct 它),而线程 B 的代码在调用 to 后立即从对象中读取,因此存在争用条件。helgrind
GetDefaultObjectForType()
GetDefaultObjectForType()
我不确定这是否是一个真实的、有朝一日会咬我的屁股的竞争条件,或者只是由于 helgrind 过于敏感而导致的假阳性,但无论哪种情况,我的问题都是一样的:我可以使用某种技术来强制对象的构造发生在(或接近)主线的顶部,即在任何线程生成之前, 因此,就调用此函数的所有线程而言,单例对象可以真正是只读的?
显然,我可以手动调用 的顶部,但这将是一个真正的维护麻烦,因为我使用了这么多不同类型的对象,以至于我可能会忘记包含某些类型(这将迫使我必须有很多头文件,我希望它不必包含)。GetDefaultObjectForType<EveryTypeIUse>()
main()
main.cpp
#include
答: 暂无答案
上一个:C++ 数据数组初始化
评论