У меня есть const float*, указывающий на огромный массив, и я хотел бы иметь доступ к элементам через std::array. Как лучше всего это сделать? Без копирования элементов, если это возможно.
Спасибо!
У меня есть const float*, указывающий на огромный массив, и я хотел бы иметь доступ к элементам через std::array. Как лучше всего это сделать? Без копирования элементов, если это возможно.
Спасибо!
Чтобы использовать std::array
, вам нужно знать размер массива во время компиляции. Вы создаете пустой массив и используете std::copy
для копирования элементов в массив.
Если код, который использует ваш const float*
, знает этот размер только во время выполнения, вы не можете использовать std::array
, но должны использовать std::vector
. std::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 */ )
{}
array_view
.
- person Davislor; 02.04.2017
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. Пожалуйста, используйте const_cast‹> только в тех случаях, когда это абсолютно неизбежно из-за недостатка во внешнем API :)
std::array
. Можете ли вы поговорить с разработчиком, чтобы улучшить API, например. грамм. вместо этого принять пару итераторов? - person zett42   schedule 26.03.2017