【问题标题】:Convert const float* to std::array<float, ...>将 const float* 转换为 std::array<float, ...>
【发布时间】:2017-03-26 12:13:48
【问题描述】:

我有一个 const float* 指向一个巨大的数组,并且希望能够通过 std::array 访问这些元素。 做这个的最好方式是什么?尽可能不复制元素。

谢谢!

【问题讨论】:

  • 如果没有未定义的行为,这是不可能的。为什么需要它?
  • 我需要构造一个对象,其构造函数中的参数之一是std::array。并且值存储在eigen的RealVectorType(eigen.tuxfamily.org/dox/…)这个类型有一个data()方法,它返回一个float*。
  • 如果类构造函数采用std::array,那么大小必须在编译时知道——对吗?你能展示你正在尝试构建的类的代码吗?
  • 如果它强制你使用std::array,你需要构造的这个对象有一个设计糟糕的API。您能否与开发人员交谈以改进 API,例如。 G。改为接受一对迭代器?
  • 是的,我知道编译时的大小。是这个类:pastebin.com/FU2vxWBS我做了,改一下就好了。

标签: c++ c++11 stdarray


【解决方案1】:

为了使用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);
}

【讨论】:

  • 宏不是遗留功能。
  • @yeoman:使用宏定义容器大小在很大程度上是现代 C++ 中的遗留特性。此外,评论根本没有说每次使用宏都意味着遗留代码。
  • 是的 :) 但是能够使用宏进行日志记录、类似断言的功能、在无异常上下文中的错误处理等。实际上是 C++ 的一个强大的语言特性。是的,C 宏是 DUMB。像 LISP 和 RUST 这样的真正的宏将是更可取的。但是完全拥有宏,尽管它的形式需要你在编写它们时真正考虑如何解析结果,这有助于避免大量样板文件,这在大多数情况下是个好主意:)
  • 是的,我其实知道尺寸。
【解决方案2】:

标准库中至少有两个提议的添加项可以做类似的事情。一个是std::experimental::to_array&lt;T,N&gt;(),它对整个数据进行深拷贝。这在时间和内存方面都是浪费的,但如果您确实想要创建一个副本,尤其是您无法创建然后修改的 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 */ )
{}

【讨论】:

  • 另外,微软还有一个名为array_view的类模板。
【解决方案3】:

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 :)

【讨论】:

    猜你喜欢
    • 2023-03-23
    • 1970-01-01
    • 2017-06-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多