【问题标题】:Treat C cstyle array as std::array将 C cstyle 数组视为 std::array
【发布时间】:2012-06-26 10:17:40
【问题描述】:

是否有任何安全且符合标准的方法可以将 C 样式数组视为 std::array 而无需将数据复制到新的 std::array 中?

这显然不能编译,但这是我想要的效果(我的实际使用更复杂,但这个简短的示例应该显示我想要做什么)。我猜 reinterpret_cast 会“工作”但可能不安全?

#include <array>

int main()
{
    int data[] = {1, 2, 3, 4, 5};

    // This next line is the important one, treating an existing array as a std::array
    std::array<int, 5>& a = data;
}

感觉这应该是可能的,因为数据应该以相同的方式存储。

编辑:要明确的是,我不想清除新的 std::array,我想将现有数据称为一个。

【问题讨论】:

  • STL 容器管理自己的内存。您不能创建一个数组并让它管理您在其他地方分配的某个数组。
  • 鉴于 std::array 和 std::vector 期望管理自己的内存,您应该非常小心使用 reinterpret_cast 而不采取措施确保他们不会尝试删除不存在的数据t 在他们的控制之下。但除此之外......不要害怕memcpy。毕竟,这是一个相当有效的例程。
  • 好的,谢谢。我想安全地做到这一点,而不是做黑客,我只是想知道这是否有可能:)
  • @krammer std::array 是一个聚合,而不是正式的容器。它没有动态分配的内存,所以内存管理很简单。
  • 我同意@Juanchopanza,我什至可以说它可以是相同的。对于 krammer 和 Rook:std::array 与 std::vector 非常不同,std::array 不会重新分配内存,它的大小是硬编码的

标签: c++


【解决方案1】:

如本文所述 Is std::array<T, S> guaranteed to be POD if T is POD?

std::array&lt;int, N&gt; 是 POD,因此是标准布局。据我了解标准布局要求,这意味着指向对象的指针与指向第一个成员的指针相同。由于 std::array 没有私有/受保护成员(根据http://en.cppreference.com/w/cpp/container/array),这应该与包装数组中的第一个元素一致。因此像

reinterpret_cast&lt; std::array&lt;int, 5&gt;* &gt;( &amp;data )

在我看来,可以保证按标准工作。不过,我必须承认,有时我在解释标准语言时有困难,所以如果我错了,请纠正我。

问候 克拉斯

【讨论】:

  • 我认为你是对的,但我会检查 array5 * p=reinterpret_cast( &data );断言(p->data() == &data);这就是我们最终想要的
【解决方案2】:

你不能那样做。 std::array 是一个聚合并保存自己的数据块(而不是指向可以轻松重新分配的数据块的指针)。所以没有办法避免所有元素的副本。在 C++11 中这一点尤为重要,因为数组的数据无法移动,因此没有高效的 std::swap 函数,例如。

【讨论】:

  • 我明白这一点。我不想用它自己的数据创建一个新的 std::array,我想引用现有数据,就好像它是一个 std::array 一样,因为它们可能是相同的布局。如果可以安全地做到这一点,那就是。我确信 reinterpret_cast “hack”会“起作用”...
  • 无论如何都赞成“对不起,你不能安全地做到这一点”是这个问题的一个很好的答案,即使不是我所希望的。
【解决方案3】:

您可以使用 reinterpret_cast,但是请注意,这是一个丑陋的肮脏 hack,您不应该在您的真实发布代码中做这样的事情:

std::array<int, 5> &a = reinterpret_cast<std::array<int, 5>&>(data);

如果 std::array 的内部实现发生变化,可能会出现问题(例如,在 STL 的调试版本中将添加一些额外的字段来进行一些运行时检查)。然后这段代码将在没有任何信息性消息的情况下开始崩溃(因为它基于一个隐含的假设,即 std::array 对象和 C 数组具有相同的内存布局)。

如果您仍然决定使用丑陋的脏 hack,至少添加一个编译时大小检查:

    C_ASSERT(sizeof(a) == sizeof(data));

如果 std::array 的大小不再匹配 C 数组的大小(由于 STL 实现中的一些更改),这将产生错误。

【讨论】:

  • 是的,我让这个“工作”。我只是想知道是否有一种方法不是丑陋的肮脏黑客:) 谢谢
  • reinterpret_cast 这个名字故意丑陋,以表明正在使用丑陋的黑客。
  • 谢谢,很好的答案。我不会用肮脏的黑客。在我的代码中有一个案例,我有一个固定大小的数组,所以想在我的代码中使用 std::array,但是我无法更改的旧代码给了我一个 c 样式的数组。我不会为此做 hack,但如果能够做一些高效且受支持的事情,那就太好了。
  • @JohnB C++ 指定 std::complex 类型的布局与 C _Complex 类型兼容,例如“表达式 reinterpret_cast&lt;cv T(&amp;)[2]&gt;(z) 应该是格式良好的,reinterpret_cast&lt;cv T(&amp;)[2]&gt;(z)[0] 应该指定真正的z的一部分”等。所以这种事情并非没有先例。 std::array 不需要与原始数组的布局兼容(例如,std::array 可能有额外的成员,在这种情况下你想要的实际上是不可能的),但如果它确实是布局兼容的,那么我会说这段代码格式良好,虽然丑陋,但不是肮脏的 hack。
  • @bames53 对reinterpret_cast 的使用可能应该以static_assert(sizeof(data) == sizeof(std::array&lt;int, 5&gt;), "std::array&lt;T, N&gt; isn't layout-compatible with T[N]."); 之类的开头。这将提供一个明确的错误消息来指示问题,有效地对演员进行未来证明(和奇怪的编译器证明)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-05-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-01-17
  • 2017-08-04
相关资源
最近更新 更多