в каждом из этих вызовов пришлось бы делать setLength(), которая будет перевыделять память/копировать из старого массива(блока памяти) в новый
Менеджер памяти всегда округляет в бОльшую сторону, выделяя кусок памяти с запасом (как конкретно - эзотерика еси). Поэтому добавление по одному элементу - это плохо, но не смертельно. Большинство вызовов SetLength() сведётся к "Ага, пока влезает, меняем только поле размера массива" - т.е. практически к стоимости самого вызова.
Та же история со строками.
На массивах/строках в десятки элементов, добавление по одному можно считать условно-бесплатным.
З.Ы. На деле, SetLength() вызывает какую-то встроенную процедуру Паскаля для задания размера массива (забыл имя), а уже та - менеджер памяти.