Does std::atomic<std::string> work appropriately?

C++AtomicStdstringStdatomic

C++ Problem Overview


I am reading through Anthony Williams' "C++ Concurrency in Action" and in Chapter 5, which talks about the new multithreading-aware memory model and atomic operations, and he states:

> In order to use std::atomic<UDT> for some user-defined UDT, this type must have a trivial copy assignment operator.

As I understand it, this means that we can use std::atomic<UDT> if the following returns true:

std::is_trivially_copyable<UDT>::value

By this logic, we shouldn't be able to use std::string as a template argument for std::atomic and have it work correctly.

However, the following code compiles and runs with expected output:

#include <atomic>
#include <thread>
#include <iostream>
#include <string>

int main()
{
	std::atomic<std::string> atomicString;

	atomicString.store( "TestString1" );

	std::cout << atomicString.load() << std::endl;

	atomicString.store( "TestString2" );

	std::cout << atomicString.load() << std::endl;

	return 0;
}

Is this a case of undefined behaviour which just happens to behave as expected?

Thanks in advance!

C++ Solutions


Solution 1 - C++

The standard does not specify a specialization of std::atomic<std::string>, so the generic template <typename T> std::atomic<T> applies. 29.5 [atomics.types.generic] p1 states:

> There is a generic class template atomic. The type of the template argument T shall be trivially copyable (3.9).

There is no statement that the implementation must diagnose violations of this requirement. So either (a) your use of std::atomic<std::string> invokes undefined behavior, or (b) your implementation provides std::atomic<std::string> as a conforming extension.

Looking at the MSDN page for std::atomic<T> (http://msdn.microsoft.com/en-us/library/vstudio/hh874651.aspx), it does explicitly mention the requirement that T be trivially copyable, and it does NOT say anything specific about std::atomic<std::string>. If it is an extension, it's undocumented. My money is on undefined behavior.

Specifically, 17.6.4.8/1 applies (with thanks to Daniel Krügler for setting me straight):

> In certain cases (replacement functions, handler functions, operations on types used to instantiate standard library template components), the C++ standard library depends on components supplied by a C++ program. If these components do not meet their requirements, the Standard places no requirements on the implementation.

std::string certainly does not meet the std::atomic<T> requirement that the template parameter T be trivially copyable, so the standard places no requirements on the implementation. As a quality of implementation issue, note that static_assert(std::is_trivially_copyable<T>::value, "std::atomic<T> requires T to be trivially copyable"); is an easy diagnostic to catch this violation.


2016-04-19 Update: I don't know when the change happened, but VS2015 Update 2 does now diagnose std::atomic<std::string>:

>

error C2338: atomic requires T to be trivially copyable.

Solution 2 - C++

No, this is undefined behavior. Moreover, since std::string is not trivially copyable, conforming compiler should have issued "at least one diagnostic message":

> 29.5 Atomic types

> There is a generic class template atomic. The type of the template argument T shall be trivially copyable (3.9).

> 1.4 Implementation compliance

> — If a program contains a violation of any diagnosable rule [...] a conforming > implementation shall issue at least one diagnostic message.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionThomas RussellView Question on Stackoverflow
Solution 1 - C++CaseyView Answer on Stackoverflow
Solution 2 - C++user3228152View Answer on Stackoverflow