【问题标题】:Initializing std::atomic_bool?初始化 std::atomic_bool?
【发布时间】:2013-03-22 23:14:45
【问题描述】:

我想使用std::atomic_bool,因为我想要一个应该被不同线程访问的布尔值。

这是一个static 成员变量。问题是我想用false 作为第一个状态来初始化它。通常我会这样做: std::atomic_bool World::mStopEvent = false;

但问题似乎是它没有将false 作为构造函数。那么我应该如何初始化这样一个变量呢? 我正在使用 VS 2012。

【问题讨论】:

    标签: c++ c++11 visual-studio-2012 atomic


    【解决方案1】:

    怎么样:

    std::atomic_bool World::mStopEvent(false);
    

    【讨论】:

    • 同样的错误:error C2440: 'initializing' : cannot convert from 'bool' to 'std::atomic_bool' 1> No constructor could take the source type, or constructor overload resolution was ambiguous
    【解决方案2】:

    这是known issue in Visual Studio 2012 (known as VC11),您应该对现有的 Connect 项目进行投票,以便 Microsoft 知道它会影响更多人,因为他们推迟了修复。

    嗨,

    感谢您报告此错误。我是 Microsoft 的 STL 维护者,我想让你知道,虽然这个错误在我们的数据库中仍然存在,但它不会在 VC11 RTM (VS 2012 RTM) 中得到修复。所有错误对我们都很重要,但有些错误比其他错误更严重,并排在我们优先级队列的顶部。

    我在 STL 的所有活动 Connect 错误中复制并粘贴此响应,但以下简洁的 cmets 专门适用于您的错误:

    • 是的,我们在atomic_boolatomic_int 等上缺少这些构造函数(atomic<bool>atomic<int> 等有它们)。 29.5 [atomics.types.generic]/7 说“应有与 atomic 的整数特化相对应的命名类型,如表 145 中所指定,以及与指定的 atomic<bool> 相对应的命名类型 atomic_bool。每个命名类型是typedef 对应的特化或对应特化的基类。如果是基类,它应该支持与对应特化相同的成员函数。这让我真的很想使用 typedef(1 种类型总是比 2 种类型简单),但我需要看看这是否会引入任何其他问题。

    我不能保证我们什么时候能够解决这个错误,但我们希望尽快解决(当发生这种情况时我会发送另一个回复) - 我们的第一个机会将是“出局” Herb Sutter 在 GoingNative 2012 会议上宣布的 VC11 和 VC12 之间的“乐队的乐队”发布。

    注意:Connect 不会通知我有关 cmets 的信息。如果您还有其他问题,请给我发电子邮件。

    斯蒂芬·T·拉瓦维 高级开发人员 - Visual C++ 库 stl@microsoft.com

    基本上,您现在需要使用std::atomic<T>

    【讨论】:

      【解决方案3】:

      问题:

      您不能使用复制初始化,因为std::atomic_bool 不可复制构造:

      std::atomic_bool World::mStopEvent = false; // ERROR!
      

      其实上面等价于:

      std::atomic_bool World::mStopEvent = std::atomic_bool(false); // ERROR!
      

      但是,您可以使用直接初始化

      std::atomic_bool World::mStopEvent(false);
      

      您可以根据自己的意愿选择使用大括号代替圆括号:

      std::atomic_bool World::mStopEvent{false};
      

      错误:

      虽然无论您选择哪种编译器,复制初始化都是非法的,但似乎 VC11 附带的标准库的实现有一个错误,不允许您执行直接初始化。

      那么我应该如何初始化这样一个变量呢?

      解决方法:

      作为一种可能的解决方法,您可以提供一对静态 getter/setter 包装器,它们分别设置和返回原子布尔标志的值,但在确保它已至少初始化一次且不超过一次以线程安全的方式到达所需的初始值(您可以考虑这是某种延迟初始化):

      #include <atomic>
      #include <mutex>
      
      struct World
      {
          static bool is_stop_event_set()
          {
              std::call_once(mStopEventInitFlag, [] () { mStopEvent = false; });
              return mStopEvent;
          }
      
          static void set_stop_event(bool value)
          {
              std::call_once(mStopEventInitFlag, [value] () { mStopEvent = value; });
              mStopEvent = value;
          }
      
          static std::atomic_bool mStopEvent;
          static std::once_flag mStopEventInitFlag;
      };
      
      std::atomic_bool World::mStopEvent;
      std::once_flag World::mStopEventInitFlag;
      

      现在不是直接访问mStopEvent,而是通过is_stop_event_set()函数读取其值:

      #include <iostream>
      
      int main()
      {
          std::cout << World::is_stop_event_set(); // Will return false
      }
      

      【讨论】:

        【解决方案4】:

        试试这个:

        atomic_bool my_bool = ATOMIC_VAR_INIT(false);
        

        http://en.cppreference.com/w/cpp/atomic/ATOMIC_VAR_INIT

        【讨论】:

        • 我认为这是最好的答案,因为它以最短的方式解决问题并且没有开销。这个解决方案也是跨平台的,我在VS和Xcode中编译过。
        • 是的,在 Mac OS X 上使用 Clang 编译,但带有警告“标量初始化程序 [-Wbraced-scalar-init] 周围的大括号”。当然,如果你启用它。
        • 自 C++11 起,在 C++20 中已弃用:(
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-10-05
        • 2016-12-22
        • 2012-02-10
        相关资源
        最近更新 更多