How to declare a vector of atomic in C++

As described in this closely related question that was mentioned in the comments, std::atomic<T> isn’t copy-constructible, nor copy-assignable.

Object types that don’t have these properties cannot be used as elements of std::vector.

However, it should be possible to create a wrapper around the std::atomic<T> element that is copy-constructible and copy-assignable. It will have to use the load() and store() member functions of std::atomic<T> to provide construction and assignment (this is the idea described by the accepted answer to the question mentioned above):

#include <atomic>
#include <vector>

template <typename T>
struct atomwrapper
{
  std::atomic<T> _a;

  atomwrapper()
    :_a()
  {}

  atomwrapper(const std::atomic<T> &a)
    :_a(a.load())
  {}

  atomwrapper(const atomwrapper &other)
    :_a(other._a.load())
  {}

  atomwrapper &operator=(const atomwrapper &other)
  {
    _a.store(other._a.load());
  }
};

int main(void)
{
  std::vector<atomwrapper<int>> v_a;
  std::atomic<int> a_i(1);
  v_a.push_back(a_i);
  return 0;
}

EDIT: As pointed out correctly by Bo Persson, the copy operation performed by the wrapper is not atomic. It enables you to copy atomic objects, but the copy itself isn’t atomic. This means any concurrent access to the atomics must not make use of the copy operation. This implies that operations on the vector itself (e.g. adding or removing elements) must not be performed concurrently.

Example: If, say, one thread modifies the value stored in one of the atomics while another thread adds new elements to the vector, a vector reallocation may occur and the object the first thread modifies may be copied from one place in the vector to another. In that case there would be a data race between the element access performed by the first thread and the copy operation triggered by the second.

Leave a Comment