22

我目前正在编写一个 C++ 内存编辑库,对于读/写 API,我使用类型特征(std::is_pod、std::is_same)和 boost::enable_if 来提供 3 个重载:

  1. POD 类型。例如 MyMem.Read(SomeAddress);
  2. 字符串类型。例如 MyMem.Read>(SomeAddress); (这实际上并没有读出 C++ 字符串,它读出了 C 风格的字符串并将其转换为 C++ 字符串。)
  3. 向量类型。例如 MyMem.Read>(SomeAddress, NumElem); (这实际上并不读出向量,而是读出 C 风格的数组并将其转换为向量。)

重载 2 和 3 只是重载 1 的“包装器”。(因此,如果您正在读取 std::vector 或 std::basic_string 并且 T 不是 POD,它将失败,因为它应该。)

最近我想使用 std::array 进行一堆读取和写入,因为我知道在编译时我想要读取和写入的数据的大小(我正在编写一个 PE 文件格式的包装器)。

我编写了使用 std::array 的代码,然后打算添加另一个重载来检测和处理 std::array 类型,但我不小心点击了编译,令我惊讶的是它起作用了!

我目前正在使用 MSVC 10,事实证明,对于 std::array,如果 T 是 POD,则 std::array 是 POD。(这意味着我可以只使用重载 1 并且它可以工作。)

我的问题是这是由 C++ 标准保证还是由实现决定。

我知道我可以自己检查标准,但我对自己的信任不如对本网站上的一些语言律师的信任,所以我认为最好获得“第二意见”。;)

谢谢

PS 代码可在此处获得(它是仅标头库): http ://code.google.com/p/hadesmem/source/browse/trunk/HadesMem-v2/Hades-Memory/Hades-Memory/MemoryMgr.h#86

4

3 回答 3

14

§23.3.1:

数组是可以使用以下语法初始化的聚合 (8.5.1),array a<T, N> = { initializer-list }; 其中 initializer-list 是一个逗号分隔的列表,最多包含 N 个元素,其类型可转换为 T。

在 C++03 中,POD 是根据聚合定义的:一个类,其中每个子对象都是本地的,或者聚合是 POD。因此,通过向后兼容性,C++0xstd::array就是 POD。

或者,作为肛门,可以将 §9/5(定义平凡的类)9/6(定义标准布局)和 9/9(将前面的要求组合到 POD)的要点与 8.5.1/ 的要点进行比较1,它定义了聚合。

8.5.1:

聚合是一个数组或类(第 9 条),没有用户提供的构造函数(12.1),没有用于非静态数据成员的大括号或等号初始化程序(9.2),没有私有或受保护的非静态数据成员(第 11 条),没有基类(第 10 条),也没有虚函数(10.3)。

实际上,第 9 条中的要求涵盖array了只要其元素类型也是 POD 并且实现在规范之外没有声明operator=move内部array

真正肛门,17.5.2.2 说

  1. 为了说明起见,第 18 到 30 条和附录 D 没有描述复制/移动构造函数、赋值运算符或(非虚拟)析构函数,它们的明显语义与默认情况下可以生成的那些相同(12.1、12.4、12.8 )。
  2. 未指定实现是否为此类成员函数签名或可以默认生成的虚拟析构函数提供显式定义。

伪代码中的注释template class array

// No explicit construct/copy/destroy for aggregate type

是否construct/copy/destroy包括operator=(作业)或move?它可能应该,但我不认为,通过最严格的阅读,它确实如此。

请注意,这不仅“影响”了 POD 特性,而且还影响了 Johannes 提到的微不足道的可复制性。

于 2010-09-09T08:02:04.083 回答
8

根据 POD 的定义:

9班

9 POD 结构是一个既是普通类又是标准布局类的类,并且没有非 POD 结构、非 POD 联合(或此类类型的数组)类型的非静态数据成员。类似地,POD 联合是一个既是普通类又是标准布局类的联合,并且没有非 POD 结构、非 POD 联合(或此类类型的数组)类型的非静态数据成员。POD 类是一个 POD 结构或 POD 联合的类。

[强调我的]

std::array确实满足了作为一个简单的标准布局类模板的所有要求。所以你的问题的答案是肯定的。

于 2010-09-09T06:58:45.757 回答
1

Potatoswatter 发现我的结论有误。C++ 显式允许实现显式定义“具有相同明显语义”的赋值运算符。这将使它成为一个非平凡的可复制类型。使其成为社区维基...


在我看来,您不想针对 PODnes 进行测试,而是针对trivially copyable进行测试,这限制较少。因为这就是 C++0x 约束类型的方式,可以memcpy和朋友一起使用。

虽然我不认为 PODness of 有任何保证std::array,但可以保证微不足道的可复制性,如下所示(如果我的结论没有错误的话)。我们知道std::array是一个聚合,聚合是

聚合是一个数组或类(第 9 条),没有用户提供的构造函数(12.1),没有用于非静态数据成员的大括号或等号初始化程序(9.2),没有私有或受保护的非静态数据成员(第 11 条),没有基类(第 10 条),也没有虚函数(10.3)。

虽然为具有以下类的类定义了平凡的可复制性

  • 没有重要的复制构造函数(12.8),
  • 没有重要的移动构造函数(12.8),
  • 没有非平凡的复制赋值运算符(13.5.3、12.8),
  • 没有非平凡的移动赋值运算符(13.5.3、12.8),并且
  • 有一个微不足道的析构函数(12.4)。

std::array没有析构函数(正如定义中的注释std::array所说)。尽管std::array的类定义中的注释声称这一点,但这似乎并没有从聚合类的定义中得出。

剩下的 4 个要求是由于缺少这 4 个聚合的特殊成员函数的基础、虚函数和用户提供的版本。

于 2010-09-09T19:26:00.037 回答