如何优雅地初始化std::atomic数组?

How do I elegantly initialize an array of std::atomic?

本文关键字:atomic 数组 std 何优雅 初始化      更新时间:2023-10-16

假设我有一个类,其成员数组为std::atomic s,其中数组的大小是通过计算来确定的(也就是说,它可能会根据程序中其他地方的常量而改变):

class Foo {
  static constexpr size_t kArraySize = ComputeArraySize();
  std::atomic<size_t> atomics_[kArraySize];
};

确保原子都初始化为最优雅的方式是什么零?我能做得比循环数组在Foo的构造函数和更好吗显式存储零?std::array的答案不同吗?

通常我会在这里使用大括号初始化式,但是派生出的长度(其中(可能很长)使它变得困难。

注意,我不能假设Foo的实例具有静态存储持续时间。

好的,我相信我已经解决了这个问题。这两个都会初始化所有的原子归零:

std::atomic<size_t> plain_array[kArraySize] = {};
std::array<std::atomic<size_t>, kArraySize> std_array = {};

逻辑如下:

  • [dcl.init。

  • [数组。cons]/1规定std::array也是一个集合

  • [dcl.init。Aggr]/7表示如果初始化器的元素较少列表中先有成员在聚合,再剩余成员从一个空的初始化列表初始化。在这种情况下,是所有成员。

  • [dcl.init。/3从一个空列表为类定义了列表初始化使用默认构造函数(如std::atomic)来引起value-initialization .

  • (dcl
  • 。/7表示没有用户提供的构造函数的类zero-initialized。假设std::array<T>包含T的数组,std::atomic<size_t>的零表示是我们所期望的,

现在,std::atomic 有一个用户提供的构造函数,只是没有用户提供的default构造函数(后者是显式默认的)。所以它在技术上不符合最后一点的条件。但是看起来在标准中是否有错误,并在最近被修正草稿。

来晚了一点。我发现自己在尝试创建原子向量时也遇到了同样的问题,正如其他用户所报告的那样,std::原子不能很好地与std::数组或std::vector库配合使用。对此,我的解决方案是创建一个包含底层原子的包装器模板类和一个创建第一个包装器类的堆分配数组的模板类。下面是我的解决方案:

#include <atomic>
template <typename T>
class Atomic_PNet
{
    public:
    std::atomic<T> member;
    Atomic_PNet::Atomic_PNet()
    {
    };
    Atomic_PNet::~Atomic_PNet()
    {
        printf("Atom deletedn");
    }
};
template <typename T>
class Atomic_Vector
{
    private:
    int vector_size;
    Atomic_PNet<T> * Atom;
    public:
    Atomic_Vector::Atomic_Vector()
    {
        vector_size = 0;
    };
    Atomic_Vector::~Atomic_Vector()
    {
        delete[] Atom;  
    
    };
    void resize(int size, T value)
    {
        if (vector_size == 0)
        {
            vector_size = size;
            Atom = new Atomic_PNet<T>[size];
        }
        for (int i =0; i < size; i++)
        {
            Atom[i].member = value;
        }
    };
    std::atomic<T> &Atomic_Vector::operator[](int index)
    {
        Atomic_PNet<T> * atm;
        atm = (Atom) + index;
        return  (atm->member);
    };
};

这里有几件事需要注意,我不打算在第一次调整大小之后改变这个类的数组大小(这是实际发生堆分配的时候)。虽然我可以编写方法在任何其他地方调整数组的大小,但我选择不这样做,因为类本身不是原子的,只有其包装的成员是原子的(这可能导致未定义的行为)。幸运的是,我的用例不要求我在任何其他点调整大小。