std :: is_trivially_copyable-为什么易失标量类型不容易复制? [英] std::is_trivially_copyable - Why are volatile scalar types not trivially copyable?

查看:168
本文介绍了std :: is_trivially_copyable-为什么易失标量类型不容易复制?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

C ++ 17的当前标准(我观察到C ++ 11的类似措词)对于琐碎可复制的类型而言,措辞非常混乱。我首先用以下代码(GCC 5.3.0)偶然发现了这个问题:

The current standards for C++17 (and I've observed similar wording for C++11) have very confusing wording for trivially copyable types. I first stumbled upon this problem with the following code (GCC 5.3.0):

class TrivialClass {};
std::is_trivially_copyable<int volatile>::value; // 0
std::is_trivially_copyable<TrivialClass volatile>::value; // 1 ??

让混乱更糟的是,我尝试检查一下 std :: is_trivial

Making the confusion even worse, I tried checking to see what std::is_trivial had to say about the matter, only being brought to more confusion.

class TrivialClass {};
std::is_trivial<int volatile>::value; // 1 ??
std::is_trivial<TrivialClass volatile>::value; // 1

我很困惑,我检查了最新的C ++ 17草案,看是否有毛病,我发现了一些可能是罪魁祸首:

Confused, I checked the latest C++17 draft to see if something was amiss, and I found some slightly ambiguous wording which might be the culprit:

http://open-std.org/JTC1/SC22/WG21/docs/papers/2015/n4567.pdf#page.73


cv不合格的标量类型,平凡可复制的类类型(第9条),此类类型的数组以及这些类型的非易失性const限定版本(3.9.3)共同称为琐碎可复制类型。

cv-unqualified scalar types, trivially copyable class types (Clause 9), arrays of such types, and non-volatile const-qualified versions of these types (3.9.3) are collectively called trivially copyable types.

以下是琐碎可复制类的信息:

Here is the information on trivially copyable classes:

http://open-std.org/JTC1/SC22/WG21 /docs/papers/2015/n4567.pdf#page.226


一个简单可复制的类是这样的类:

A trivially copyable class is a class that:

—(6.1)没有非平凡的副本构造rs(12.8),

— (6.1) has no non-trivial copy constructors (12.8),

—(6.2)没有非平凡的构造函数(12.8),

— (6.2) has no non-trivial move constructors (12.8),

—(6.3)没有非平凡的构造平凡的副本分配运算符(13.5.3,12.8),

— (6.3) has no non-trivial copy assignment operators (13.5.3, 12.8),

—(6.4)没有非平凡的移动分配运算符(13.5.3,12.8)和

— (6.4) has no non-trivial move assignment operators (13.5.3, 12.8), and

—(6.5)有一个琐碎的析构函数(12.4)。

— (6.5) has a trivial destructor (12.4).

> http://open-std.org/JTC1/SC22/WG21/docs/papers/2015/n4567 .pdf#section.12.8

构造函数:


副本如果类X的/ move构造函数不是由用户提供的,则它是微不足道的,它的parameter-type-list等效于隐式声明的parameter-type-list,并且如果

A copy/move constructor for class X is trivial if it is not user-provided, its parameter-type-list is equivalent to the parameter-type-list of an implicit declaration, and if

— (12.1)X类没有虚拟函数(10.3)和虚拟基类(10.1),并且

— (12.1) class X has no virtual functions (10.3) and no virtual base classes (10.1), and

—(12.2)X类没有的非静态数据成员挥发性限定类型

— (12.2) class X has no non-static data members of volatile-qualified type, and

—(12.3)构造选择复制/移动每个直接基类子对象的操作很简单,并且

— (12.3) the constructor selected to copy/move each direct base class subobject is trivial, and

-(12.4)对于类类型(或其数组)的X的每个非静态数据成员,选择要复制/移动该成员的构造函数是微不足道的;

— (12.4) for each non-static data member of X that is of class type (or array thereof), the constructor selected to copy/move that member is trivial;

否则,复制/移动构造函数是不平凡的。

otherwise the copy/move constructor is non-trivial.

赋值:


如果X类不是用户提供的,则复制/移动赋值运算符很简单。 parameter-type-list等效于隐式声明的parameter-type-list,并且如果

A copy/move assignment operator for class X is trivial if it is not user-provided, its parameter-type-list is equivalent to the parameter-type-list of an implicit declaration, and if

—(25.1)类X没有虚拟函数(10.3)也没有虚拟基类(10.1)和

— (25.1) class X has no virtual functions (10.3) and no virtual base classes (10.1), and

—(25.2)类X没有没有挥发性限定类型的非静态数据成员,并且

— (25.2) class X has no non-static data members of volatile-qualified type, and

-(25.3)选择用来复制/移动每个直接基类子对象的赋值运算符很简单,

— (25.3) the assignment operator selected to copy/move each direct base class subobject is trivial, and

-(25.4)对于X的每个非静态数据成员而言是类类型(或其数组)的选择要复制/移动该成员的赋值运算符是微不足道的;

— (25.4) for each non-static data member of X that is of class type (or array thereof), the assignment operator selected to copy/move that member is trivial;

否则,复制/移动赋值运算符是不平凡的。

otherwise the copy/move assignment operator is non-trivial.

注意:更新了本节,提供了更多信息。我现在认为这是GCC中的错误。

我可以看到也许是因为TrivialClass没有非静态成员,因为它可以通过上述规则,所以

I could see that maybe it's because TrivialClass has no non-static members, as that would pass the above rules, so I added an int, and it still returns as trivially copyable.

class TrivialClass { int foo; };
std::is_trivially_copyable<int volatile>::value; // 0
std::is_trivially_copyable<TrivialClass volatile>::value; // 1 ??

标准指出volatile应该由volatile对象的子对象继承。含义 TrivialClass volatile 的非静态数据成员 foo 现在应为 int volatile类型

The standard states that volatile should be inherited by sub-objects of a volatile object. Meaning TrivialClass volatile's non-static data member foo should now be of type int volatile.

http://open-std.org/JTC1/SC22/WG21/docs/papers/2015/n4567.pdf#page.76


易失性对象是volatile T类型的对象,该对象的子对象或const易失性对象的可变子对象

A volatile object is an object of type volatile T, a subobject of such an object, or a mutable subobject of a const volatile object

我们可以通过以下方式确认它是否在GCC中起作用:

We can confirm this is working in GCC via:

std::is_same<decltype(((TrivialClass volatile*)nullptr)->foo), int volatile>::value; // 1! (Expected)

很困惑,然后我在 int foo 本身。它仍然可以通过,这显然是一个错误!

Confused, I then added a volatile to int foo itself. It still passes, which is obviously a bug!

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=68905#c1

class TrivialClass { int volatile foo; };
std::is_trivially_copyable<int volatile>::value; // 0
std::is_trivially_copyable<TrivialClass volatile>::value; // 1 ??

继续,我们看到 std :: is_trivial 也是

http://open-std.org/JTC1/SC22/WG21/docs/papers/2015/n4567.pdf#page.73


标量类型,琐碎类类型(第9条),此类类型的数组以及这些类型的cv限定版本(3.9.3)统称为琐碎类型。

Scalar types, trivial class types (Clause 9), arrays of such types and cv-qualified versions of these types (3.9.3) are collectively called trivial types.

好的,所以我在这里有很多问题。

Okay, so I have a lot of questions here.


  • 为什么对is_trivially_copyable来说是易变的而不是is_trivial?

  • is_trivially_copyable和对象类型有什么关系,这是标准的错误还是问题?

  • 无论如何,如果有什么波动,为什么如此重要?

  • Why does volatile matter for is_trivially_copyable and not is_trivial?
  • What's the deal with is_trivially_copyable and object types, is it a bug or an issue with the standard?
  • Why does it matter if something is volatile anyways?

有人可以帮我解决这个问题吗? ,我真的很茫然。

Can anyone help me wrap my head around this, I'm really at a loss here.

解决方案

显然,这是解决标准缺陷的一种方式,但您不是唯一对此感到困惑的人。

Apparently it's the way a defect in the standard was fixed, but you're not the only one confused about it.

来自 http://www.open-std.org/jtc1/ sc22 / wg21 / docs / cwg_active.html#2094



  1. 临时复制/移动具有易变成员的类的构造函数

节:12.8 [class.copy]状态:open提交者:Daveed Vandevoorde日期:2015-03-06

Section: 12.8 [class.copy] Status: open Submitter: Daveed Vandevoorde Date: 2015-03-06

问题496的解决方案包括
加上12.8 [class.copy]第25.2段,如果一个类的
复制/移动构造函数具有非volatile限定类型的静态数据成员
。此更改破坏了IA-64 ABI,因此要求
CWG重新考虑该决议的这一方面。

The resolution of issue 496 included the addition of 12.8 [class.copy] paragraph 25.2, making a class's copy/move constructor non-trivial if it has a non-static data member of volatile-qualified type. This change breaks the IA-64 ABI, so it has been requested that CWG reconsider this aspect of the resolution.

在相关说明中,问题496的决议也已更改3.9
[basic.types]第9段,使限定挥发成分的标量类型
平凡,而不是平凡可复制。目前尚不清楚为什么在这里有
的区别;
标准中平凡类型的唯一实际用法似乎是在qsort的描述中,
应该使用平凡可复制。 (另请参见问题1746。)

On a related note, the resolution of issue 496 also changed 3.9 [basic.types] paragraph 9, which makes volatile-qualified scalar types "trivial" but not "trivially copyable." It is not clear why there is a distinction made here; the only actual use of "trivial type" in the Standard appears to be in the description of qsort, which should probably use "trivially copyable." (See also issue 1746.)

摘自问题描述(自2004年12月30日起):

From the description of issue (from 30.12.2004):



  1. 一个限定挥发的类型真的是POD吗? :

但是在3.9 [basic.types]第3段中,该标准明确指出
可以仿佛复制POD是
memcpy收集的字节:

However in 3.9 [basic.types] paragraph 3, the standard makes it clear that PODs can be copied "as if" they were a collection of bytes by memcpy:

对于任何POD类型T,如果指向T的两个指针指向不同的T对象
obj1和obj2,而obj1都不obj2也不是基类子对象,如果使用std :: memcpy
库函数将obj1的值复制到obj2中,则
随即与obj1保持相同的值。
的问题是,可能需要以特定方式复制
挥发性限定类型(例如,通过仅在
多线程平台上使用原子操作进行复制),以避免逐字节复制可能会发生内存
撕裂。

For any POD type T, if two pointers to T point to distinct T objects obj1 and obj2, where neither obj1 nor obj2 is a base-class subobject, if the value of obj1 is copied into obj2, using the std::memcpy library function, obj2 shall subsequently hold the same value as obj1. The problem with this is that a volatile qualified type may need to be copied in a specific way (by copying using only atomic operations on multithreaded platforms, for example) in order to avoid the "memory tearing" that may occur with a byte-by-byte copy.

我意识到该标准对挥发性合格的
类型几乎没有说什么,什么也没有根本上还没有关于多线程平台的信息,但是
仍然是一个真正的问题,原因如下:

I realise that the standard says very little about volatile qualified types, and nothing at all (yet) about multithreaded platforms, but nonetheless this is a real issue, for the following reason:

即将推出的TR1将定义一系列特性,这些特性可提供有关以下方面的信息:类型的属性,包括类型是否为POD和/或具有微不足道的构造/复制/分配操作。库可以使用此信息适当地优化其代码,例如,如果T是POD,则可以使用memcpy复制T类型的数组,而不是逐元素复制。这是TR1型特征一章背后的主要动机之一。但是尚不清楚在这些情况下应如何处理易失性类型(或具有易失性类型的POD)。2005年4月会议的注意事项:

The forthcoming TR1 will define a series of traits that provide information about the properties of a type, including whether a type is a POD and/or has trivial construct/copy/assign operations. Libraries can use this information to optimise their code as appropriate, for example an array of type T might be copied with a memcpy rather than an element-by-element copy if T is a POD. This was one of the main motivations behind the type traits chapter of the TR1. However it's not clear how volatile types (or POD's which have a volatile type as a member) should be handled in these cases.Notes from the April, 2005 meeting:

目前尚不清楚是否挥发性限定词实际上以这种方式保证原子性。同样,Evolution Working Group正在针对多线程的内存模型进行的工作似乎可能会为易失性数据指定其他语义,并且在解决此问题之前需要考虑该工作。

It is not clear whether the volatile qualifier actually guarantees atomicity in this way. Also, the work on the memory model for multithreading being done by the Evolution Working Group seems at this point likely to specify additional semantics for volatile data, and that work would need to be considered before resolving this issue.

这篇关于std :: is_trivially_copyable-为什么易失标量类型不容易复制?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆