D Динамическая инициализация массива, шаг и операция индекса
Вопрос
Извините, это стало в трехкратный вопрос относительно массивов
Я думаю, что (динамические) массивы действительно сильны в D, но следующее меня какое -то время беспокоило:
В C ++ я мог легко выделить массив с назначенными значениями, но в DI не нашел способ сделать это. Конечно, следующее не является проблемой:
int[] a = new int[N];
a[] = a0;
Но это выглядит неэффективно, поскольку первая линия будет инициализироваться с 0
, и как 2 с a0
. Анкет Можно ли сделать что -то похожее на следующее в D?
int[] a = new int(a0)[N]; // illegal
Еще один вопрос эффективности, который у меня есть при использовании шага в std.range:
import std.stdio;
import std.range;
struct S
{
int x;
this(this)
{
writeln("copy ", x);
}
}
void f(S[] s)
{
}
int main()
{
S[] s = new S[10];
foreach (i, ref v; s)
{
v.x = i;
}
f(stride(s, 3)); // error
return 0;
}
Конечно, я был наивен, думая, что могу просто использовать шаг, чтобы создать новый массив, не копируя его элементы? В D нет способа сделать это, верно?
Поэтому я пошел и смоделировал, как если бы массив был так же, как и шаг, и реализовано f
в качестве:
f(s, 3);
void f(S[] s, uint stride)
{
ref S get(uint i)
{
assert (i * stride < s.length);
return s[i * stride];
}
for (uint x ... )
{
get(x) = ...;
}
}
Будет ли способ вместо этого написать (x), используя оператор индекса get[x]
? Таким образом, я мог бы статически смешать / включить ход get
функционируйте и держите остальную часть функции одинаковой. Я был бы заинтересован в принятом подходе, поскольку локальной структуре не разрешается получить доступ к переменным сферу функции (почему бы и нет?).
Решение
Но это выглядит неэффективно, так как первая линия будет инициализироваться с 0, а 2 - с A0. Можно ли сделать что -то похожее на следующее в D?
Использовать std.array.uninitializedArray
S[] s = uninitializedArray!(S[])(N);
s[] = a0;
Конечно, я был наивен, думая, что могу просто использовать шаг, чтобы создать новый массив, не копируя его элементы? В D нет способа сделать это, верно?
Ваша функция f
имеет S[]
как аргумент, который отличается от того, что stride
возврат. D Способ решить это - сделать ваш f
Функция принимайте любой диапазон, сделав его шаблоном:
void f(Range)(Range s)
{
foreach (item; s)
// use item
}
S[] s = new S[10];
f(s); // works
f(stride(s, 3)); // works too
В качестве альтернативы вы можете скопировать массив:
f(array(stride(s, 3)));
Но вы, вероятно, хотите избежать копирования всего массива, если он большой.
Будет ли способ вместо этого написать Get (x) с помощью оператора индекса GET [x]? Таким образом, я мог бы статически смешать / включить функцию ход и сохранить остальную часть функции одинаковой. Я был бы заинтересован в принятом подходе, поскольку локальной структуре не разрешается получить доступ к переменным сферу функции (почему бы и нет?).
Вы можете перегрузить оператора индексации в собственном структуре.
struct StrideArray
{
this(S[] s, uint stride) { m_array = s; m_stride = stride; }
S opIndex(size_t i) { return s[i * m_stride]; }
void opIndexAssign(size_t i, S value) { s[i * m_stride] = value; }
private S[] m_array;
private uint m_stride;
}
Это (своего рода) способ фактического stride
функция работает. Я бы порекомендовал прочитать на Диапазоны.
Другие советы
Вы можете дублировать (создать копию) массива с .dup (это также будет работать с ломтиками) или вы можете установить элементы с помощью инициализатора массива
int[] a=a0.dup;
int[] b=[e1,e2,e3];
Вы можете сделать f generic (stride () возвращает структуру, которую вы можете перевернуть, а не массив)
void f(Z)(Z s)if(isInputRange!Z){
foreach(elem;s){
//...
}
}
Помните, что массивы по существу являются поставками с полем указателя в некотором блоке памяти и полем размера