一个std::array的地址是否保证与其数据相同?

11
std::array是一个聚合类型,其语义与持有C风格数组T[N]作为仅非静态数据成员的结构体相同(引自cppreference)。
这是否意味着数组的地址始终与其第一个元素的地址相同,即data()
#include <array>
#include <iostream>

int main()
{
    std::array<int,6> x{};
    std::cout << &x << "\n";
    std::cout << x.data();
}

可能的输出:

0x7ffc86a62860
0x7ffc86a62860

如果是这样,那么有什么用处吗?下面的操作是否允许?
int* p = reinterpret_cast<int*>(&x);
for (int i=0;i<6;++i){ std::cout << p[i]; }

1
为什么你想要执行reinterpret_cast<int*>(&x)而不是只使用x.data()呢? - Alan Birtles
C语言有一个规则,即任何struct的地址都等于其第一个成员的地址,并且可以安全地将指向其中一个的指针转换为另一个。C++对于class是否有相同的规则呢?我不太确定在标准中应该查找哪个部分。 - Nate Eldredge
实际上,我没有在标准中看到“仅非静态数据成员”的规定;标准似乎并没有排除其他成员。是cppreference编造的吗? - Nate Eldredge
你正在对标准定义的类的内部布局做出假设。像这些东西一样,标准没有明确说明内部布局应该是什么(我也看不到它只有一个数据成员的任何提及)。 - 1201ProgramAlarm
@1201ProgramAlarm 我承认我对cppref视而不见了。如果你能引用标准并且它没有说array是唯一数据成员,那就已经证明了我的假设是错误的。 - 463035818_is_not_a_number
显示剩余6条评论
1个回答

16
从技术上讲,一个std::array对象的开头可能会有填充字节,在这种情况下,数据将位于比std::array对象更高的地址。只有标准布局类才保证对象本身与第一个非静态数据成员具有相同的地址。
标准中没有保证std::array<T, N>是标准布局的,即使Tint或类似的类型。所有合理的std::array<T, N>实现都将具有单个类型为T[N]的非静态数据成员、没有虚函数和最多一个继承链而且没有虚基类,这意味着只要T本身是标准布局的,它们就是标准布局的。另外,即使T不是标准布局的,编译器也不太可能在std::array对象的开头插入填充字节。
因此,尽管假设一个std::array<T, N>对象与它包含的第一个T对象具有相同的地址是不可移植的,在实践中基本上是可以保证的。您可以添加一个static_assert(sizeof(std::array<T, N>) == sizeof(T[N]));来确保,如果有人试图在一个不支持这种情况的奇异实现上构建您的代码,他们将知道它不被支持。

标准确实说std::array是一个聚合体,那么这是否意味着标准布局? - Remy Lebeau
2
@RemyLebeau 聚合和标准布局是不同的概念。你可以拥有一个非标准布局的聚合体。 - NathanOliver
@RemyLebeau 我认为差不多,但并非完全相同。聚合类可以有多个相同类型的(公共)基类子对象。标准布局类则不能。当然,在 std::array 的情况下,没有合理的实现会这样做。 - Brian Bi
@RemyLebeau:我认为它是一种聚合体,因为它是一个没有用户声明或继承构造函数、没有私有或受保护的直接非静态数据成员等的类。但这并不意味着它的成员实际上是什么。我认为标准允许 class std::array<T,N> { public: int miscellaneous_junk; T actual_array[N]; }; - Nate Eldredge
4
那个具体的实现不符合规范。其中杂项垃圾成员会干扰聚合初始化。 - Brian Bi
1
那个具体的实现不符合规范,你忘了加上 "如果该实现没有特殊的初始化规则用于 std::array"。[一个 array 是一个聚合体,它可以通过最多 N 个元素进行列表初始化,这些元素的类型可以转换为 T](https://timsong-cpp.github.io/cppwp/n4868/array#overview-2)。只要实现支持这一点,`std::array` 的内容就可以有任何垃圾在开头。就像将 std::complex 数组重新解释为两倍长度的 float/double 数组违反了 [expr.add] / 4,实现可能会违反[dcl.init.aggr]的 array - Language Lawyer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接