【问题标题】:Initialisation of vector of atomics原子向量的初始化
【发布时间】:2019-11-04 22:03:59
【问题描述】:

考虑:

void foo() {
  std::vector<std::atomic<int>> foo(10);
  ...
}

foo 的内容现在有效吗?还是我需要显式循环并初始化它们?我已经检查过 Godbolt,它似乎很好,但是在这一点上标准似乎很混乱。

std::vector 构造函数说它插入了std::atomic&lt;int&gt;default-inserted 实例,这些实例是value initialised 通过放置new

我认为值初始化的这种效果适用:

2) 如果 T 是具有既不是用户提供也不是删除的默认构造函数的类类型(也就是说,它可能是具有隐式定义或默认构造函数的类),则该对象为零初始化并且如果它有一个非平凡的默认构造函数,那么它是默认初始化的;

所以在我看来,原子是零初始化的。那么问题来了,std::atomic&lt;int&gt; 的零初始化是否会产生一个有效的对象?

我猜答案是“在实践中是的,但它并没有真正定义”?

注意:This answer 同意它是零初始化的,但并没有真正说明这是否意味着该对象是有效的。

【问题讨论】:

    标签: c++ vector atomic


    【解决方案1】:

    你的担心是正确的。根据标准,原子调用了默认构造函数,但是它们没有被初始化。这是因为默认构造函数没有初始化原子:

    默认初始化的std::atomic&lt;T&gt;不包含T对象, 它唯一有效的用途是销毁和初始化 std::atomic_init

    这在某种程度上违反了正常的语言规则,并且某些实现无论如何都会初始化(正如您所指出的)。

    话虽如此,我还是建议您采取额外的步骤,以确保 100% 确保它们按照标准正确初始化 - 毕竟您正在处理并发问题,而其中的错误极难追踪。

    有很多方法可以避免这个问题,包括使用包装器:

    struct int_atomic {
       std::atomic<int> atomic_{0};//use 'initializing' constructor
    };
    

    【讨论】:

    • 或者实际使用atomic_init。无论如何,您已经必须围绕问题中的代码进行同步
    • 默认构造函数是微不足道的,所以它不会调用(根据问题中的引用)
    • @LightnessRaceswithMonica 这也是可能的,我只是想突出显示包装器
    • @LightnessRaceswithMonica 这是正常语言规则的一个例外——即使一些编译器没有实现这个例外。我不确定 StoreTeller 的回答是否 100% 准确。
    【解决方案2】:

    即使调用了默认构造函数(不是,因为它很简单)it doesn't really do anything

    零初始化显然不能保证产生一个有效的原子;这仅在偶然通过零初始化其所有成员创建有效原子时才有效。

    而且,由于原子不可复制,因此您不能在向量构造函数中提供初始化值。

    您现在应该循环遍历容器和 std::atomic_init 每个元素。如果您需要锁定这一点,那很好,因为出于同样的原因,您已经在同步向量的创建。

    【讨论】:

    • @darune 我认为这是一种同步 ;)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-03-04
    • 2011-05-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-25
    相关资源
    最近更新 更多