将 const float* 转换为 std::array<float, ...>
Convert const float* to std::array<float, ...>
我有一个 const float* 指向一个巨大的数组,并且希望能够通过 std::array 访问元素。
做这个的最好方式是什么?尽可能不复制元素。
谢谢!
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<> 以防你确定指针实际上不是 const float。请仅在由于外部 API 缺陷而绝对不可避免的情况下使用 const_cast<> :)
为了使用std::array
,你需要在编译时知道数组的大小。您创建一个空数组并使用 std::copy
将元素复制到数组中。
如果使用 const float*
的代码在运行时只知道该大小,那么您不能使用 std::array
,而必须使用 std::vector
。 std::vector
有一个构造函数,您可以将指向范围开始和结束的指针传递给该构造函数以将其复制到其中。
请注意,在这两种情况下,容器 拥有原始元素的副本。
Without copying the elements if possible.
不,那是不可能的。 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
副本,则可能会有用。
如果您想要的是一个容器接口,用于连接由任意指针和元素计数表示的一系列数据,Guideline Support Library 提供了一个 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 */ )
{}
我有一个 const float* 指向一个巨大的数组,并且希望能够通过 std::array 访问元素。 做这个的最好方式是什么?尽可能不复制元素。
谢谢!
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<> 以防你确定指针实际上不是 const float。请仅在由于外部 API 缺陷而绝对不可避免的情况下使用 const_cast<> :)
为了使用std::array
,你需要在编译时知道数组的大小。您创建一个空数组并使用 std::copy
将元素复制到数组中。
如果使用 const float*
的代码在运行时只知道该大小,那么您不能使用 std::array
,而必须使用 std::vector
。 std::vector
有一个构造函数,您可以将指向范围开始和结束的指针传递给该构造函数以将其复制到其中。
请注意,在这两种情况下,容器 拥有原始元素的副本。
Without copying the elements if possible.
不,那是不可能的。 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
副本,则可能会有用。
如果您想要的是一个容器接口,用于连接由任意指针和元素计数表示的一系列数据,Guideline Support Library 提供了一个 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 */ )
{}