【问题标题】:"Downcasting" a std::atomic_ref<T>“向下转换” std::atomic_ref<T>
【发布时间】:2021-11-25 08:10:34
【问题描述】:

是否可以在std::atomic_ref&lt;T&gt;std::atomic_ref&lt;U&gt; 之间向下转换,其中UT 的子类?

我尝试了以下代码,但没有成功。

template<typename T>
std::atomic_ref<T> World::getComponentByID(componentInstanceId uuid) const {
    static componentTypeId key = stringHash(typeid(T).name());
    return components.at(uuid);
}

模板参数T 是位置(Component 的子类)。 componentscomponentInstanceIds 到 Components 的映射。

error C2440: 'return': cannot convert from 'const std::atomic_ref&lt;Component&gt;' to 'std::atomic_ref&lt;Position&gt;

【问题讨论】:

  • 我认为您的意思是“向上转型”而不是“向下转型”?
  • 我正在从超类 Component 转换为子类 Position @ruakh。
  • 我明白了。在那种情况下,我很惊讶您尝试了您所做的代码,据我所知,C++ never 允许隐式向下转换。我错过了什么吗?
  • From cppreference: "atomic_ref 对象引用的对象的子对象不能同时被任何其他atomic_ref 对象引用。"这意味着有一个 atomic_ref 引用派生类的一个对象和另一个引用其基类子对象的行为将是未定义的行为,正如您设想的强制转换所需要的那样。
  • 您尝试做的事情对我来说没有任何意义。听起来像XY problem。你为什么要通过atomic_ref 持有components - 是否以某种方式同时访问它们?您在哪里以及如何存储这些引用所引用的实际 Component 对象?显示minimal reproducible example

标签: c++ multithreading casting stdatomic


【解决方案1】:

以这种方式使用atomic_ref 没有意义。 (即使在汇编语言中有意义的lock_free 情况下,ISO C++ 标准也没有公开该功能。)

正如@Igor Tandetnik 指出的那样,“由 atomic_ref 对象引用的对象的子对象不能同时被任何其他 atomic_ref 对象引用。”

此规则存在的一个原因是,对于非无锁atomic_ref,它实现了互斥池,因此拥有具有不同指针值的子对象将使您进入子对象的不同互斥锁,甚至是互斥锁来自不同的池,或者可能发生子对象是无锁的,但更大的对象是基于锁的。

此外,可能的指针调整可能会导致对齐失败,atomic_ref 引用的值必须尊重 atomic_ref&lt;T&gt;::required_alignment


atomic_ref 不是通用工具。也许您只需要使用std::mutexstd::shared_mutex 来保护您的对象。

【讨论】:

  • 以这种方式使用 atomic_ref 没有意义。 如果整个对象和子对象都是 lock_free 的,那么它在实际 CPU 上的 asm 中确实有意义,并且如果编写正确,将在 C++ 中作为 hack 工作。我不会说它没有意义,而是说这是 ISO C++ 未公开的 asm 功能。
  • How can I implement ABA counter with c++11 CAS? 类似的问题,您需要高效读取,但当前编译器不会优化 16 字节 atomic 的读取,然后仅使用 1 个成员到仅 8 字节加载.我在atomic&lt;16byte&gt; 和两个atomic&lt;8-byte&gt; 的结构之间用union 破解了它,这显然在ISO C++ 中没有明确定义,但可以编译为良好的asm。这一切都是因为编译器对16byte.load().member很烂。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-10-20
  • 2016-03-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-05-05
  • 1970-01-01
相关资源
最近更新 更多