Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Initialisation of vector of atomics

Tags:

c++

atomic

vector

Consider:

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

Are the contents of foo now valid? Or do I need to explicitly loop through and initialise them? I have checked on Godbolt and it seems fine, however the standard seems to be very confused on this point.

The std::vector constructor says it inserts default-inserted instances of std::atomic<int>, which are value initialised via placement new.

I think this effect of value initialisation applies:

2) if T is a class type with a default constructor that is neither user-provided nor deleted (that is, it may be a class with an implicitly-defined or defaulted default constructor), the object is zero-initialized and then it is default-initialized if it has a non-trivial default constructor;

So it seems to me that the atomics are zero-initialised. So the question is, does zero-initialisation of a std::atomic<int> result in a valid object?

I'm going to guess that the answer is "yes in practice but it's not really defined"?

Note: This answer agrees that it is zero-initialised, but doesn't really say if that means that the object is valid.

like image 676
Timmmm Avatar asked Nov 04 '19 12:11

Timmmm


2 Answers

You are correct to be worried. According to standard the atomics has the default constructor called, however they have not been initialized as such. This is because the default constructor doesn't initialize the atomic:

The default-initialized std::atomic<T> does not contain a T object, and its only valid uses are destruction and initialization by std::atomic_init

This is somewhat in violation of the normal language rules, and some implementations initialize anyway (as you have noted).

That being said, I would recommend taking the extra step to make 100% sure they are initialized correctly according to standard - after all you are dealing with concurrency where bugs can be extremely hard to track down.

There are many ways to dodge the issue, including using wrapper:

struct int_atomic {
   std::atomic<int> atomic_{0};//use 'initializing' constructor
};
like image 142
darune Avatar answered Sep 20 '22 16:09

darune


Even if the default constructor were called (it isn't, because it's trivial) it doesn't really do anything.

Zero-initialisation obviously cannot be guaranteed to produce a valid atomic; this'll only work if by chance a valid atomic is created by zero-initialising all its members.

And, since atomics aren't copyable, you can't provide a initialisation value in the vector constructor.

You should now loop over the container and std::atomic_init each element. If you need to lock around this, that's fine because you're already synchronising the vector's creation for the same reason.

like image 44
Lightness Races in Orbit Avatar answered Sep 19 '22 16:09

Lightness Races in Orbit