将 const float* 转换为 std::array<float, ...>

Convert const float* to std::array<float, ...>

本文关键字:float lt gt array std const 转换      更新时间:2023-10-16

我有一个指向巨大数组的常量浮点*,并希望能够通过 std::array 访问元素。最好的方法是什么?如果可能,无需复制元素。

谢谢!

为了使用std::array,你需要在编译时知道数组的大小。创建一个空数组并使用 std::copy 将元素复制到数组中。

如果使用您的const float*的代码在运行时只知道该大小,那么您不能使用std::array,而必须使用std::vectorstd::vector有一个构造函数,您可以将指针传递到范围的开头和结尾以复制到其中。

请注意,在这两种情况下,容器都拥有原始元素的副本。

如果可能,无需复制元素。

不,这是不可能的。C++标准容器旨在拥有其内容,而不仅仅是表示其中的视图。

下面是一个说明差异的示例:

#define SIZE 10 // let's assume some C or legacy code which uses macros
// ...
void f(const float* arr)
{
    // size is known at compile time
    std::array<float, SIZE> a;
    std::copy(arr, arr + SIZE, begin(a));
}
void g(const float* arr, int size)
{
    // size is only known at runtime
    std::vector<float> v(arr, arr + size);
}

标准库中至少有两个建议的添加功能可以做类似的事情。 一种是std::experimental::to_array<T,N>(),它制作了整个数据的深层副本。 这在时间和内存方面都是浪费的,但如果您确实想要创建副本,尤其是无法创建然后修改的const副本,则可能会很有用。

如果您想要的是由任意指针和元素计数表示的数据范围的容器接口,指南支持库提供了一个span模板。 我建议,如果你同时传递两者,你把它们包装在一个类似于这个的轻量级对象中。

既然你说你可以将接口更改为构造函数,我强烈建议你这样做。 如果要保留采用std::array的版本,则可以将其委托给采用任意数据范围的版本,例如:

#include <algorithm>
#include <array>
#include <iterator>
#include "span"
MyClass::MyClass( const span<value_type>& s /*, more, params */ )
{ 
 /* In this example, m_storage is some private container and span has a
  * container interface.
  */
  auto it = std::back_inserter(m_storage);
  std::copy_n( s.begin(), s.size(), it );
  // ...
}
MyClass::MyClass( std::array<value_type, initializer_size>& a /*, more, params */ )
: MyClass( span<value_type>( a.data(), a.size() ) /*, more, params */ )
{}

std::array 不拥有指针的所有权。您必须复制元素。使用 std::copy。它适用于抽象迭代器,指针也符合这些条件。

const float *source = ...; // C array of at least of size N
std::array<float, N> destination;
std::copy(source, source + N, destination.begin());

顺便说一句:在不复制元素的情况下,任何支持获取指针所有权的容器的元素类型也必须是 const float。或者,如果您确定指针实际上不是真正的常量浮动,则必须使用const_cast<>。请仅在由于外部 API 中的缺陷而绝对不可避免的情况下使用 const_cast<> :)