Nothing in C ++ is thread-dependent¹ unless explicitly stated .
If you need to read object c while it can be modified in another thread, you are responsible for blocking it. This is a general rule, and there is no reason why reading it in order to create a copy should be an exception.
Please note that the created copy should not be blocked, because no other thread knows about it yet. Only the source should be.
The compiler does not guarantee that something can be thread safe, because 99.9% of things should not be thread safe. Most things only need to be repeated. Therefore, in the rare case, you really need to do something thread safe, you should use locks ( std::mutex ) or atomic types ( std::atomic<int> ).
You can also just make your objects persistent, and then you can read them without locking because nothing writes them after they are created. Code that uses persistent objects is more easily parallelized and more easily understood in general, because there are fewer things with state that you need to track.
Note that in the most common architecture, the mov command with int operands is thread safe. On other types of CPUs, even this may not be true. And since the compiler is allowed to preload values, an integer assignment in C ++ is not in any case.
¹ A set of operations is considered thread safe if it is correctly called on the same object2. In C ++, calling any modification operation and any other operation simultaneously on the same object is a data race, which is UndefinedBehavior ™.
² It is important to note that if the facility is "thread safe", this does not really help you in most cases. Because if the object guarantees that when it is written at the same time, you will always read the new or old value (C ++ allows you to read another stream, say 232 , when changing int c from 0 to 1000 , a large one Part of the time, this will not help you, because you need to read several values in a consistent state, for which you still have to block them yourself.
³ Reentrant means that the same operation can be called up simultaneously on different objects. There are several functions in the C standard library that are not reentrant because they use global (static) buffers or some other state. Most of them have reentrant options (usually with the suffix _r ), and the standrd C ++ library uses them, so part of C ++ is usually reentrant.