D инициализация динамического массива, шаг и индекс операции - PullRequest
4 голосов
/ 03 декабря 2011

Извините, это стало трехкратным вопросом относительно массивов.

Я думаю, что (динамические) массивы действительно мощные в D, но некоторое время меня беспокоило следующее:

ВC ++ Я мог бы легко выделить массив с обозначенными значениями, но в D я не нашел способа сделать это.Конечно, следующие проблемы не представляют проблемы:

int[] a = new int[N];
a[] = a0;

Но это выглядит неэффективно, поскольку строка 1 будет инициализироваться с 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) = ...;
    }
}

Можно ли вместо этого написать get (x), используя оператор индекса get[x]?Таким образом, я мог бы статически смешивать / включать функцию шага get и сохранять остальные функции похожими.Я был бы заинтересован в выбранном подходе, поскольку локальной структуре не разрешен доступ к переменным области действия функции (почему бы и нет?).

Ответы [ 2 ]

7 голосов
/ 03 декабря 2011

Но это выглядит неэффективно, так как строка 1 будет инициализироваться с 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]?Таким образом, я мог бы статически смешивать / включать функцию get шага и сохранять остальные функции похожими.Меня заинтересует выбранный подход, поскольку локальной структуре не разрешен доступ к переменным области действия функции (почему бы и нет?).

Вы можете перегрузить оператор индексации в своей собственной структуре.

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.Я бы порекомендовал читать по Диапазоны .

1 голос
/ 03 декабря 2011

вы можете продублировать (создать копию) массив с помощью .dup (это также будет работать со слайсами) или вы можете установить элементы с помощью инициализатора массива

int[] a=a0.dup;
int[] b=[e1,e2,e3];

вы можете сделать f универсальным(stride () возвращает структуру, по которой вы можете перебирать, а не массив)

void f(Z)(Z s)if(isInputRange!Z){
    foreach(elem;s){
         //...
    }
}

помните, что массивы - это по существу структуры с полем указателя на некоторый блок памяти и полем размера

...