是 std::array如果 T 是 POD,就保证是 POD?

发布于 2024-09-19 03:31:22 字数 1102 浏览 5 评论 0原文

我目前正在编写一个 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++ 标准保证的还是由实现决定。

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

谢谢

) 此处提供代码(这是一个仅包含标头的库): http ://code.google.com/p/hadesmem/source/browse/trunk/HadesMem-v2/Hades-Memory/Hades-Memory/MemoryMgr.h#86

I'm currently writing a C++ memory editing library and for the read/write APIs I use type traits (std::is_pod, std::is_same) and boost::enable_if to provide 3 overloads:

  1. POD types. e.g. MyMem.Read(SomeAddress);
  2. String types. e.g. MyMem.Read>(SomeAddress); (This doesn't actually read out a C++ string, it reads out a C-style string and converts it to a C++ string.)
  3. Vector types. e.g. MyMem.Read>(SomeAddress, NumElem); (This doesn't actually read out a vector, rather it reads out a C-style array and converts it to a vector.)

Overloads 2 and 3 are simply 'wrappers' around overload 1. (So if you're reading a std::vector or std::basic_string and T is not POD it will fail, as it should.)

Recently I wanted to use std::array for a bunch of reads and writes because I knew the size of the data I wanted to read and write at compile time (I was writing a wrapper around the PE file format).

I wrote the code to use std::array, and then intended to add another overload for detection and handling of std::array types, but I accidentally hit compile and to my surprise it worked!

I'm currently using MSVC 10 and it turns out that for std::array if T is POD then std::array is POD. (Which means I can just use overload 1 and it works.)

My question is whether this is guaranteed by the C++ standard or left up to the implementation.

I know I could check the standard myself, but I don't trust myself as much as I trust some of the language lawyers on this site, so I figured it would be best to get a 'second opinion'. ;)

Thanks

P.S. Code available here (it's a header-only lib):
http://code.google.com/p/hadesmem/source/browse/trunk/HadesMem-v2/Hades-Memory/Hades-Memory/MemoryMgr.h#86

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

居里长安 2024-09-26 03:31:23

根据 POD 的定义:

9 类

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

[强调我的]

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

By definition of POD:

9 Classes

9 A POD struct is a class that is both a trivial class and a standard-layout class, and has no non-static data members of type non-POD struct, non-POD union (or array of such types). Similarly, a POD union is a union that is both a trivial class and a standard layout class, and has no non-static data members of type non-POD struct, non-POD union (or array of such types). A POD class is a class that is either a POD struct or a POD union.

[Emphasis mine]

std::array does satisfy all the requirements of being a trivial, standard-layout class template. So the answer to your question is yes.

愿与i 2024-09-26 03:31:23

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



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

虽然我认为对于 std::array 的 PODness 没有任何保证,但有保证关于琐碎的可复制性,如下所示(如果我的结论没有错误)。我们知道 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 个特殊成员函数的基础、虚拟函数和用户提供的版本。

Potatoswatter found an error in my conclusions. C++ explicitly allows an implementation to explicitly define an assignment operator "with the same apparent semantics". This will make it a non-trivially copyable type. Making it community wiki...



It seems to me you don't want to test against PODnes, but against trivially copyable, which is way less restricting. Because that is how C++0x constraints types that can be used with memcpy and friends.

And while I don't think there are any guarantees about PODness of std::array, there are guarantees about trivial copyability, as the following shows (if I haven't got an error in the conclusions). As we know std::array is an aggregate, and aggregates are

An aggregate is an array or a class (Clause 9) with no user-provided constructors (12.1), no brace-or-equal-
initializers for non-static data members (9.2), no private or protected non-static data members (Clause 11),
no base classes (Clause 10), and no virtual functions (10.3).

While trivially copyability is defined for a class that has class that

  • has no non-trivial copy constructors (12.8),
  • has no non-trivial move constructors (12.8),
  • has no non-trivial copy assignment operators (13.5.3, 12.8),
  • has no non-trivial move assignment operators (13.5.3, 12.8), and
  • has a trivial destructor (12.4).

std::array has no destructor (as a comment in the definition of std::array says). This does not seem to follow from the definition of aggregate classes though, even though the comment in std::array's class definition claims that.

The remaining 4 requirements follow from the absence of bases, virtual functions and user provided versions for those 4 special member functions for aggregates.

再见回来 2024-09-26 03:31:22

§23.3.1:

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

在C++03中,POD是根据聚合定义的:一个类,其中每个子对象都是本机的或聚合是POD。因此,通过向后兼容性,C++0x std::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 。除了规范之外,code>array。

真正肛门,17.5.2.2 说

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

模板类数组伪代码中的注释是

// 聚合类型没有显式构造/复制/销毁

construct/copy/destroy 是否包含 operator= (赋值)或 move ?它可能应该,但我认为,通过最严格的阅读,它不会。

请注意,这不仅“影响”POD 性,而且还影响 Johannes 提到的琐碎可复制性。

§23.3.1:

An array is an aggregate (8.5.1) that can be initialized with the syntax array a<T, N> = { initializer-list };
where initializer-list is a comma separated list of up to N elements whose types are convertible to T.

In C++03, POD was defined in terms of aggregate: a class where every subobject is native or an aggregate is POD. So, by backwards compatibility, a C++0x std::array is POD.

Or, to be anal, one can compare the bullet-points of §9/5 (defining trivial class) 9/6 (defining standard-layout) and 9/9 (combining preceding requirements into POD) with those of 8.5.1/1, which defines aggregates.

8.5.1:

An aggregate is an array or a class (Clause 9) with no user-provided constructors (12.1), no brace-or-equal- initializers for non-static data members (9.2), no private or protected non-static data members (Clause 11), no base classes (Clause 10), and no virtual functions (10.3).

Indeed the requirements in Clause 9 cover array as long as its element type is also POD and the implementation does not declare operator= or move inside array in addition to the specifications.

To be really anal, 17.5.2.2 says

  1. For the sake of exposition, Clauses 18 through 30 and Annex D do not describe copy/move constructors, assignment operators, or (non-virtual) destructors with the same apparent semantics as those that can be generated by default (12.1, 12.4, 12.8).
  2. It is unspecified whether the implementation provides explicit definitions for such member function signa- tures, or for virtual destructors that can be generated by default.

The note in the pseudo-code for template class array is

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

Does construct/copy/destroy include operator= (assignment) or move? It probably should, but I don't think, by the strictest reading, it does.

Note that this "affects" not only POD-ness, but also trivial copyability as Johannes mentions.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文