Подходы с присвоением больших сложных массивов
От: Khimik  
Дата: 04.09.23 15:50
Оценка: :)
У меня перестала запускаться моя программа, и я ищу ошибки в старом дерьмокоде, написанном 20 лет назад. Видно что общей ошибкой было частое использование указателей и всяких new, dispose, getmem, freemem, вместо использования классов. Другая ошибка заключалась в том, что вместо assign-ов использовалось копирование указателей на сложные структуры. Предположим, у вас есть сложный иерархический массив с разными вложенными элементами, а в другой модуле сопряжённый с ним другой массив (например первый массив хранит данные для логики программы, а второй для их визуального отображения на формах). Так вот надо при присвоении вторым массивом первого прописывать процедуру assign, а у меня раньше могло быть копирование указателей на структуру (тогда, если сделать присвоение а потом первый массив очистить, то второй перестанет нормально работать).
Мне показалось, у многих Delphi-программистов встречается ещё большая дичь – обычное присвоение для переменных с типом стандартные динамические массивы. Вот тут показано к чему это может привести:

  Скрытый текст
program test;

var x, y: array of integer;

procedure show(a: array of integer; n: string);
var i: Integer;
begin
    write(n, ':');
    for i := Low(a) to High(a) do
        write(' ', a[i]);
    writeln;
end;

begin
    SetLength(x, 3);
    x[0] := 1;
    x[1] := 2;
    x[2] := 3;
    y := x;
    show(x, 'x в начале');
    show(y, 'y в начале нацелено на x');
    y[2] := 10;
    show(x, 'поэтому изменение y изменяет и x');
    SetLength(x, 4);
    x[2] := 20;
    x[3] := 30;
    show(x, 'x теперь другой массив');
    show(y, 'y от него уже отцепился');
end.



Не знаю, есть ли похожие штуки в C.
Данные переменной длины обычно лучше хранить в виде классов. Если к классу добавляется новое поле переменной длины (класс, динамический массив, строка), надо поправить код в трёх местах: инициализация в конструкторе, освобождение в деструкторе и ассигн в ассигне. Для простых данных можно использовать рекорды (кажется в C они называются статическими классами), у них преимущества два – скорость и не нужно каждый раз вызывать конструктор/деструктор.
Как я уже написал, обычно надо прописывать ассигны для присвоений сложных переменных. Но если важна скорость, может всё-таки лучше быть не полное присвоение, а копирование указателя. У меня есть такой случай. Нужно нарисовать молекулу в виде множества сфер (атомов). Чтобы рисовалось быстрее, имеет смысл для каждого атома нарисовать его картинку заранее, и потом копировать нарисованное на экран. При этом обычно все атомы одинаковы, поэтому для всех, например, атомов углерода достаточно нарисовать одну картинку. С другой стороны, иногда атомы могут содержать трехмерные надписи, и тогда необходимо для каждого атома в молекуле нарисовать отдельную картинку. Ассигнить эти картинки неправильно, потому что в молекуле может быть тысяча атомов одинакового типа, тут надо не ассигнить а нарисовать один раз и присваивать указатели. Но нужно тщательно следить за ошибками, чтобы не начать рисовать на невыделенной памяти, и освобождать вовремя память, чтобы не было утечек. Подскажите, для этого годятся умные указатели? Напомните, что это такое.
"Ты должен сделать добро из зла, потому что его больше не из чего сделать". АБ Стругацкие.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.