std::is_trivially_copyable - 为什么易失性标量类型不可简单复制?

2024-05-06

C++17 的当前标准(我观察到 C++11 的类似措辞)对于普通可复制类型的措辞非常混乱。我首先使用以下代码(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不得不说这件事,只会让事情变得更加混乱。

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

很困惑,我检查了最新的 C++17 草案,看看是否有什么问题,我发现了一些稍微含糊的措辞,这可能是罪魁祸首:

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

cv 未限定标量类型、普通可复制类类型(第 9 条)、此类类型的数组以及这些类型的非易失性 const 限定版本 (3.9.3) 统称为普通可复制类型。

以下是有关可简单复制的类的信息:

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

普通可复制类是这样的类:

— (6.1) 没有重要的复制构造函数 (12.8),

— (6.2) 没有重要的移动构造函数 (12.8),

— (6.3) 没有重要的复制赋值运算符 (13.5.3, 12.8),

— (6.4) 没有非平凡的移动赋值运算符 (13.5.3, 12.8),并且

— (6.5) 有一个简单的析构函数 (12.4)。

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

构造函数:

如果类 X 的复制/移动构造函数不是用户提供的,则它是微不足道的,其参数类型列表相当于隐式声明的参数类型列表,并且如果

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

— (12.2) X 类有没有 volatile 限定类型的非静态数据成员, and

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

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

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

任务:

如果不是用户提供的,则类 X 的复制/移动赋值运算符是微不足道的,其参数类型列表相当于隐式声明的参数类型列表,并且如果

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

— (25.2) X 类有没有 volatile 限定类型的非静态数据成员, and

— (25.3) 选择用于复制/移动每个直接基类子对象的赋值运算符是微不足道的,并且

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

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

注意:使用更多信息更新了本节。我现在相信这是 GCC 中的一个错误。然而,仅此并不能回答我所有的问题。

我可以看到,也许是因为 TrivialClass 没有非静态成员,因为这会通过上述规则,所以我添加了一个 int,它仍然返回为普通可复制的。

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

该标准规定,易失性应该由易失性对象的子对象继承。意义TrivialClass volatile的非静态数据成员foo现在应该是类型int volatile.

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

易失性对象是 易失性 T 类型的对象、此类对象的子对象或 const 易失性对象的可变子对象

我们可以通过以下方式确认这在 GCC 中有效:

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

很困惑,然后我添加了一个 volatile 到int foo本身。还是过去了,这明显是bug啊!

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=68905#c1 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 http://open-std.org/JTC1/SC22/WG21/docs/papers/2015/n4567.pdf#page.73

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

好吧,我这里有很多问题。

  • 为什么 volatile 对 is_trivially_copyable 重要而不对 is_trivial 重要?
  • is_trivially_copyable 和对象类型有什么关系,是错误还是标准问题?
  • 无论如何,如果某些东西是不稳定的,那为什么很重要呢?

谁能帮我解决这个问题,我真的很茫然。


显然,这是修复标准中的缺陷的方式,但您并不是唯一对此感到困惑的人。

From https://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2094 https://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2094:

  1. 具有易失性成员的类的简单复制/移动构造函数

部分:12.8 [class.copy] 状态:开放 提交者:Daveed Vandevoorde 日期:2015-03-06

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

相关说明,第 496 号问题的决议也更改了 3.9 [basic.types] 第 9 段,它构成了 volatile 限定的标量类型 “微不足道”但不是“微不足道的可复制”。目前尚不清楚为什么会有 这里做了区分;中唯一实际使用“琐碎类型” 标准似乎在 qsort 的描述中,应该 可能会使用“简单可复制”。 (另见第 1746 期。)

根据问题描述(2004年12月30日起):

  1. 易失性限定类型真的是 POD 吗? :

然而,在 3.9 [basic.types] 第 3 段中,该标准明确指出 POD 可以被复制,“就好像”它们是字节的集合 内存复制:

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

我意识到该标准很少提到挥发性合格 类型,并且对多线程平台一无所知,但是 尽管如此,这是一个真正的问题,原因如下:

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

目前尚不清楚 volatile 限定符是否真的以这种方式保证原子性。此外,进化工作组正在进行的多线程内存模型工作似乎目前可能为易失性数据指定额外的语义,并且在解决此问题之前需要考虑这项工作。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

std::is_trivially_copyable - 为什么易失性标量类型不可简单复制? 的相关文章

  • 部署 MVC4 项目时出错:找不到文件或程序集

    过去 我只需使用 Visual Studio 2012 发布到 AWS 菜单项即可部署我的 MVC4 网站 到 AWS Elastic Beanstalk 现在 程序可以在本地编译并运行 但无法部署 从消息来看 它似乎正在寻找不在当前部署的
  • 创建 DirectoryEntry 实例以供测试使用

    我正在尝试创建 DirectoryEntry 的实例 以便可以使用它来测试将传递 DirectoryEntry 的一些代码 然而 尽管进行了很多尝试 我还是找不到实例化 DE 并初始化它的 PropertyCollection 的方法 我有
  • 自动从 C# 代码进行调试过程并读取寄存器值

    我正在寻找一种方法来读取某个地址的 edx 注册表 就像这个问题中所问的那样 读取eax寄存器 https stackoverflow com questions 16490906 read eax register 虽然我的解决方案需要用
  • 如何在 WPF RichTextBox 中跟踪 TextPointer?

    我正在尝试了解 WPF RichTextBox 中的 TextPointer 类 我希望能够跟踪它们 以便我可以将信息与文本中的区域相关联 我目前正在使用一个非常简单的示例来尝试弄清楚发生了什么 在 PreviewKeyDown 事件中 我
  • 使用 Google Analytics API 在 C# 中显示信息

    我一整天都在寻找一个好的解决方案 但谷歌发展得太快了 我找不到有效的解决方案 我想做的是 我有一个 Web 应用程序 它有一个管理部分 用户需要登录才能查看信息 在本节中 我想显示来自 GA 的一些数据 例如某些特定网址的综合浏览量 因为我
  • c 中的错误:声明隐藏了全局范围内的变量

    当我尝试编译以下代码时 我收到此错误消息 错误 声明隐藏了全局范围内的变量 无效迭代器 节点 根 我不明白我到底在哪里隐藏或隐藏了之前声明的全局变量 我怎样才能解决这个问题 typedef node typedef struct node
  • 当 Cortex-M3 出现硬故障时如何保留堆栈跟踪?

    使用以下设置 基于 Cortex M3 的 C gcc arm 交叉工具链 https launchpad net gcc arm embedded 使用 C 和 C FreeRtos 7 5 3 日食月神 Segger Jlink 与 J
  • 基于范围的 for 循环中的未命名循环变量?

    有没有什么方法可以不在基于范围的 for 循环中 使用 循环变量 同时也避免编译器发出有关未使用它的警告 对于上下文 我正在尝试执行以下操作 我启用了 将警告视为错误 并且我不想进行像通过在某处毫无意义地提及变量来强制 使用 变量这样的黑客
  • 使用安全函数在 C 中将字符串添加到字符串

    我想将文件名复制到字符串并附加 cpt 但我无法使用安全函数 strcat s 来做到这一点 错误 字符串不是空终止的 我确实设置了 0 如何使用安全函数修复此问题 size strlen locatie size nieuw char m
  • 编译的表达式树会泄漏吗?

    根据我的理解 JIT 代码在程序运行时永远不会从内存中释放 这是否意味着重复调用 Compile 表达式树上会泄漏内存吗 这意味着仅在静态构造函数中编译表达式树或以其他方式缓存它们 这可能不那么简单 正确的 他们可能是GCed Lambda
  • Windows 10 中 Qt 桌面应用程序的缩放不当

    我正在为 Windows 10 编写一个简单的 Qt Widgets Gui 应用程序 我使用的是 Qt 5 6 0 beta 版本 我遇到的问题是它根本无法缩放到我的 Surfacebook 的屏幕上 这有点难以判断 因为 SO 缩放了图
  • 网络参考共享类

    我用 Java 编写了一些 SOAP Web 服务 在 JBoss 5 1 上运行 其中两个共享一个类 AddressTO Web 服务在我的 ApplycationServer 上正确部署 一切都很顺利 直到我尝试在我的 C 客户端中使用
  • C 中的位移位

    如果与有符号整数对应的位模式右移 则 1 vacant bit will be filled by the sign bit 2 vacant bit will be filled by 0 3 The outcome is impleme
  • AccessViolationException 未处理

    我正在尝试使用史蒂夫 桑德森的博客文章 http blog stevensanderson com 2010 01 28 editing a variable length list aspnet mvc 2 style 为了在我的 ASP
  • EPPlus Excel 更改单元格颜色

    我正在尝试将给定单元格的颜色设置为另一个单元格的颜色 该单元格已在模板中着色 但worksheet Cells row col Style Fill BackgroundColor似乎没有get财产 是否可以做到这一点 或者我是否必须在互联
  • 作为字符串的动态属性名称

    使用 DocumentDB 创建新文档时 我想设置属性名称动态地 目前我设置SomeProperty 像这样 await client CreateDocumentAsync dbs db colls x new SomeProperty
  • 方法参数内的变量赋值

    我刚刚发现 通过发现错误 你可以这样做 string s 3 int i int TryParse s hello out i returns false 使用赋值的返回值是否合法 Obviously i is but is this th
  • 将变量分配给另一个变量,并将一个变量的更改反映到另一个变量中

    是否可以将一个变量分配给另一个变量 并且当您更改第二个变量时 更改会瀑布式下降到第一个变量 像这样 int a 0 int b a b 1 现在 b 和 a 都 1 我问这个问题的原因是因为我有 4 个要跟踪的对象 并且我使用名为 curr
  • C++ 成员函数中的“if (!this)”有多糟糕?

    如果我遇到旧代码if this return 在应用程序中 这种风险有多严重 它是一个危险的定时炸弹 需要立即在应用程序范围内进行搜索和销毁工作 还是更像是一种可以悄悄留在原处的代码气味 我不打算writing当然 执行此操作的代码 相反
  • 如何将字符串“07:35”(HH:MM) 转换为 TimeSpan

    我想知道是否有办法将 24 小时时间格式的字符串转换为 TimeSpan 现在我有一种 旧时尚风格 string stringTime 07 35 string values stringTime Split TimeSpan ts new

随机推荐