54

我正在阅读 Anthony Williams 的“C++ Concurrency in Action”和第 5 章,其中讨论了新的多线程感知内存模型和原子操作,他说:

为了std::atomic<UDT>用于一些用户定义的UDT,这个类型必须有一个普通的复制赋值操作符。

据我了解,这意味着std::atomic<UDT>如果以下返回 true,我们可以使用:

std::is_trivially_copyable<UDT>::value

按照这种逻辑,我们不应该将其std::string用作模板参数std::atomic并使其正常工作。

但是,以下代码编译并运行并显示预期输出:

#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;
}

这是一种未定义行为的情况,只是恰好按预期运行吗?

提前致谢!

4

2 回答 2

60

该标准未指定 的特化std::atomic<std::string>,因此适用泛型template <typename T> std::atomic<T>。29.5 [atomics.types.generic] p1 状态:

有一个通用类模板原子。模板参数 T 的类型应该是可简单复制的(3.9)。

没有声明实现必须诊断违反此要求的情况。因此,要么(a)您使用std::atomic<std::string>调用未定义的行为,要么(b)您的实现提供std::atomic<std::string>作为符合标准的扩展。

查看std::atomic<T>http://msdn.microsoft.com/en-us/library/vstudio/hh874651.aspx)的 MSDN 页面,它确实明确提到了T可以简单复制的要求,并且没有说明任何具体的std::atomic<std::string>. 如果它是一个扩展,它是无证的。我的钱用于未定义的行为。

具体来说,适用 17.6.4.8/1(感谢 Daniel Krügler 让我直截了当):

在某些情况下(替换函数、处理函数、用于实例化标准库模板组件的类型的操作),C++ 标准库依赖于 C++ 程序提供的组件。如果这些组件不满足其要求,则标准对实施没有要求。

std::string当然不满足std::atomic<T>模板参数T可简单复制的要求,因此标准对实现没有要求。作为一个实施质量问题,请注意这static_assert(std::is_trivially_copyable<T>::value, "std::atomic<T> requires T to be trivially copyable");是一个简单的诊断方法来捕捉这种违规行为。


2016-04-19 更新:我不知道变化是什么时候发生的,但是 VS2015 Update 2 现在可以诊断std::atomic<std::string>

错误 C2338:原子要求 T 可以轻松复制。
于 2013-06-01T22:10:08.317 回答
13

不,这是未定义的行为。此外,由于 std::string 不是简单可复制的,因此符合标准的编译器应该发出“至少一条诊断消息”:

29.5 原子类型

有一个通用类模板原子。模板参数 T 的类型应该是可简单复制的(3.9)。

1.4 执行合规性

— 如果程序包含对任何可诊断规则的违反[...],则符合要求的实现应发出至少一个诊断消息。

于 2014-01-23T14:34:59.033 回答