d2: разница между выделением массива через new и назначением литерала массива


Рассмотрим следующий код:

class C {
    immutable(double[][]) data;

    this() {
        immutable(double[])[] blocks = [];
        immutable(double)[] block;

        foreach (x; 0 .. 5) {
            block = [];

            block ~= 0.1 * x;
            block ~= 1.0 * x;
            block ~= 10.0 * x;

            blocks ~= block;
        }

        this.data = blocks;
    }
}

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

Действительно ли назначение литерала массива выделяет память правильным образом или лучше использовать что-то вроде new double[0]? Разве нет некоторых оговорок при переназначении одного и того же литерала?

2 2
d2

2 ответа:

Присвоение пустому литералу имеет тот же эффект, что и присвоение нулю. Он не выделяет никакой памяти. Выделение происходит, когда вы объединяетесь в "блок". Это приводит к перераспределению массива три раза, я думаю, что если значения статически известны, то он может быть оптимизирован дальше. В любом случае, я бы, вероятно, предварительно выделил "блок" с 3 элементами только один раз, затем назначил соответствующие элементы каждой итерации и конкат в "блоки" (он будет выполнять копию здесь). Я ожидаю, что вы не знаете ... значение" x " статично. Если вы это сделаете, вы также можете статически инициализировать емкость для "блоков".

Назначение [] ничего не выделяет. Это то же самое, что назначить null или вообще не инициализировать динамический массив. Это делает его таким, что массив имеет length из 0 и ptr, который является null. Только когда свойство массива ptr ненулевое, он имеет какую-либо выделенную ему память.

В таком виде вы можете просто переместить объявление block в строку, где вы назначаете его [], и избавиться от назначения. Как бы то ни было, вы напрасно повторно используете переменная снова и снова. Поскольку он используется только в цикле, это единственное место, где он должен существовать.

Если вы хотите уменьшить вероятность дополнительных перераспределений массива при добавлении к нему, то либо используйте reserve или std.array.appender.

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