【问题标题】:Initialize atomic members in aggregate聚合初始化原子成员
【发布时间】:2018-02-17 03:22:50
【问题描述】:

似乎没有办法使用 C++14 来初始化原子成员。以下不起作用(live on gcc 8.0.1):

#include <atomic>
#include <iostream>

struct stru {
  std::atomic_int32_t val_0;
  std::atomic_int32_t val_1;
};

int main() {
  auto p = new stru{0, 1};
  std::cout << p->val_0 << ", " << p->val_1 << std::endl; 
}

错误信息:

error: use of deleted function 'std::atomic<int>::atomic(const std::atomic<int>&)'
   auto p = new stru{0, 1};
                     ^

这是因为原子类型既不可复制也不可移动,因此不可复制初始化。但是,以下似乎可行(live on gcc 8.0.1)。

#include <atomic>
#include <iostream>

struct stru {
  std::atomic_int32_t val_0;
  std::atomic_int32_t val_1;
};

int main() {
  auto p = new stru{};
  std::cout << p->val_0 << ", " << p->val_1 << std::endl; 
}

这有效地执行零初始化,因此无法初始化为零以外的值。有没有办法初始化为其他指定的值?

【问题讨论】:

  • 不要发布链接到你的编译器spew,发布spew。
  • 您的第一个代码块在 VS2017 上编译时没有警告/错误,并按预期运行。我错过了什么吗?
  • @jwdonahue 如果不同的编译器不同意,那么一个是正确的,另一个是错误的。众所周知,VS 不符合标准。顺便说一句,你所说的 post the spew 是什么意思?
  • 他的意思是把错误信息放在问题里。
  • 你试过VS选项/std:c++14来指定你想要的语言版本吗? :-)

标签: c++ c++14 language-lawyer stdatomic aggregate-initialization


【解决方案1】:

Patrick 的 solution 有效,但他的解释在我看来并不正确。所以我发布了我在这里找到的解释。对于代码auto p = new stru{{0}, {1}}; aggregate initialization 的效果:

如果初始化子句是嵌套的花括号初始化列表(不是 一个表达式),对应的数组元素/类成员/public base (C++17 起) 从该子句列表初始化:聚合 初始化是递归的。

因此,成员不是复制初始化,而是从花括号初始化列表复制列表初始化。

【讨论】:

  • 相关:Copy constructor for classes with atomic member:如果您正在编写自定义构造函数(常规构造函数或(可能是一个坏主意)复制构造函数):请务必使用 :atomic_member(a) 语法将 args 传递给 std::atomic 构造函数,而不是在让原子成员默认初始化后在构造函数中使用原子存储(赋值)。
  • @PeterCordes 确实如此。不过,我有点担心atomic_flag。似乎只有std::atomic_flag v = ATOMIC_FLAG_INIT; 语法可以保证工作(见here)。所以,我想知道:atomic_member(a) 是否可以,还是我必须使用类内默认成员初始化器。
  • 我说的是std::atomic&lt;T&gt;模板; std::atomic_flag 被标准允许不同,我认为因为它是唯一保证无锁的。 :atomic_member(a) 绝对没问题(并且对于典型的 C++ 实现中的 int / long 和其他小的 T 类型是无锁的)。 :atomic_flag_member(a) 甚至不能保证编译,因为 std::atomic_flag 没有值构造函数。 (它可能在不需要特殊的实现上编译,并在std::atomic&lt;bool&gt; 之上定义;标准允许它是特殊的。)
  • 当你说“成员是从花括号初始化列表复制初始化”时——在这种情况下选择哪个构造函数?
  • @PatrickCollins 这意味着如果选定的构造函数声明为explicit,则程序格式错误。例如,unique_ptr&lt;int&gt; p = {new int()} 不会编译。
【解决方案2】:

1 和 0 不是 std::atomic_int32_ts。以下作品:

#include <atomic>
#include <iostream>

struct stru {
  std::atomic_int32_t val_0;
  std::atomic_int32_t val_1;
};

int main() {
  auto p = new stru{{0}, {1}};
  std::cout << p->val_0 << ", " << p->val_1 << std::endl; 
}

编辑:为什么会这样? Copy initialization kicks in 用于初始化列表中的每个元素:

每个直接公共...非静态类成员,按照类定义中数组下标/外观的顺序,从初始化列表的相应子句复制初始化。

在您的示例中,1 和0 被隐式转换为std::atomic_int32_t,而std::atomic_int32_t 不能从std::atomic_int32_t 复制初始化。在额外的{} 版本中,val_0 和val_1 是从std::initializer_list&lt;int&gt;s 复制初始化的,这很好。

【讨论】:

  • 你能解释一下这里发生的细节吗?
  • 我不认为你的解释是正确的。我已经发布了我找到的解释。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-06-23
  • 1970-01-01
  • 1970-01-01
  • 2015-01-22
  • 1970-01-01
  • 2020-05-25
  • 2015-11-15
相关资源
最近更新 更多