Как инициализировать статические массивы в D без выделения GC?

В D все литералы массива являются динамическими массивами и поэтому выделяются GC.

Даже в этом простом примере:

int[3] a = [10, 20, 30];

Массив выделен в кучу и затем скопирован в a.

Как вы должны инициализировать статический массив без выделения кучи?

Вы можете сделать это вручную:

int[3] a = void;
a[0] = 10;
a[1] = 20;
a[2] = 30;

Но в лучшем случае это утомительно.

Есть ли лучший способ?

Ответ 1

static const int[3] a = [10, 20, 30];

Это поместит постоянную копию в сегмент данных. Вы можете создать копию в стеке (которая не включает выделение кучи) с простым назначением (auto copy = a;).

Ответ 2

Я думаю, что если бы вы могли объявить литерал как immutable глобально, тогда используйте это как инициализатор, там не будет выделение кучи - но я могу ошибаться, я не уверен.

Ответ 3

Я думаю, вы можете ошибаться: http://www.digitalmars.com/d/2.0/arrays.html#static-init-static

Статическая инициализация статических массивов

Статические инициализации представлены списком значений элементов массива заключен в []. Значениям может быть необязательно предшествует индекс и a:. Если индекс не указан, он устанавливается на предыдущий индекс плюс 1 или 0, если это первое значение.

-snip -

Эти массивы являются статическими, когда они отображаются в глобальной области. В противном случае они должны быть отмечены с помощью константных или статических классов хранения, чтобы сделать их статическими массивами.

с примером кода

int[3] a = [ 1:2, 3 ]; // a[0] = 0, a[1] = 2, a[2] = 3

это означает, что const a[3] = [10, 20, 30]; не будет/не должен выделять ничего в куче

Ответ 4

Это просто ошибка компилятора. Я видел это в DMD bugzilla. Он должен быть исправлен к настоящему времени (DMD 2.055).

Ответ 5

2017 UPDATE: в любой последней версии DMD использование инициализатора массива в статическом массиве больше не выделяется, даже если статический массив является локальной переменной (то есть распределением по стеклу).

Вы можете проверить это самостоятельно, создав функцию, в которой инициализируется статический массив, а затем помечает функцию как @nogc и наблюдает, компилирует ли она. Пример:

import std.random;
import std.stdio;
int[4] testfunc(int num) @nogc
{
    return [0, 1, num, 3];
}

int main()
{
    int[4] arr = testfunc(uniform(0, 15));
    writeln(arr);
    return 0;
}

Так как testfunc() компилируется, несмотря на @nogc, мы знаем, что инициализатор массива не выделяет.