Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[3.85.85.246] |
|
Сообщ.
#1
,
|
|
|
У меня задача:
В проекте может быть множество Single массивов, все одинакового размера. С массивами выполняются разнообразные простые операции, например, массивы можно почленно сложить или перемножить. Эти действия оформлены в отдельные процедуры. Крайне желательно, чтобы при наборе кода, использующего процедуры, работал IntelliSense, и чтобы процедуры не принимали параметром другие Single массивы. Я обернул массив в тип: Public Type tTF Ar() As Single End Type Так выглядит процедура сложения массивов: Public Sub tTFAdd(Dst As tTF, Src1 As tTF, Src2 As tTF) Dim i As Long For i = 0 To TFSize - 1 Dst.Ar(i) = Src1.Ar(i) + Src2.Ar(i) Next i End Sub TFSize, как нетрудно догадаться, это общий размер массивов. Работает быстро, ничего лишнего в процедуру не подсунешь, но такой подход вынуждает каждый массив инициализировать: Public Sub tTFNew(T As tTF) ReDim T.Ar(TFSize - 1) End Sub Эту инициализацию можно случайно пропустить - получим ошибку. Я мог бы в типе указать сразу фиксированный размер массива, но VB6 не даёт задавать в типе фиксированный размер более 64 Кб, что крайне мало. Тогда я решил завернуть массивы не в тип, а в класс. Но в классе нельзя сделать Public массив, приходится делать свойство для доступа к элементам массива. Защищенность повысилась, теперь массив инициализируется автоматически, но скорость упала в 35-40 раз, а для меня этот параметр очень важен. Подскажите, есть ли ещё какой-то путь решения моей задачи, который я упустил? Прилагаю тестовый проект: Прикреплённый файлSpdTest.zip (6,06 Кбайт, скачиваний: 48) |
Сообщ.
#2
,
|
|
|
Цитата Mikle @ такой подход вынуждает каждый массив инициализировать Ну потому что подход - ущербный. Попробуй нечто вроде вот такого: Public Function tTFAdd(Dst As tTF, Src1 As tTF, Src2 As tTF) As Boolean Dim i As Long Dim arSize As Long On Error Goto ErrorHandler tTFAdd = False arSize = Ubound(Src1.Ar) If arSize <> Ubound(Src2.Ar) Then Exit Function ' removed If arSize <> Ubound(Dst.Ar) Then ReDim Dst.Ar(arSize - 1) ' removed End If For i = 0 To arSize - 1 Dst.Ar(i) = Src1.Ar(i) + Src2.Ar(i) Next i tTFAdd = True Exit Function ErrorHandler: Err.Clear End Function Во-первых, контроль равности исходных массивов. Во-вторых, переопределение при необходимости массива-приёмника. В третьих, возвращаемое значение позволяет убедиться, что процесс прошёл нормально, и результат корректен. |
Сообщ.
#3
,
|
|
|
Пока массив не инициализирован, Ubound не сработает, поможет ли On Error? надо будет проверить, я включаю оптимизацию "Remove Array Bounds Checks", при такой работе с массивами это немалая прибавка скорости.
И таких процедур будут десятки, с разным кол-вом аргументов-массивов, и в каждом делать такую проверку... впрочем её можно вынести в процедуру проверки с переменным числом аргументов. |
Сообщ.
#4
,
|
|
|
Цитата Mikle @ Пока массив не инициализирован, Ubound не сработает С другой стороны, содержимое массива назначения по-любому потеряется, есть оно или нет его... может, вместо проверки на размерность делать безусловный ReDim? См. поправленный код. |
Сообщ.
#5
,
|
|
|
Цитата Akina @ может, вместо проверки на размерность делать безусловный ReDim? Для приёмника сгодится, а для источников? А если приёмник так же является одним из источников? Вообще, в идеале, было бы хорошо иметь возможность менять TFSize в середине программы, так, чтобы размер всех массивов при этом тоже менялся, пусть с потерей данных. Вижу это в случае, когда массив обёрнут в класс, класс в Initialise автоматически регистрируется в некой коллекции, для смены TFSize есть процедура TFReSize (общая, в модуле), эта процедура проходит по коллекции и редимит все массивы. Если создавать классы-массивы As New, то дальше всё работает красиво, автоматически и без излишеств, только вот вопрос быстродействия остаётся. Можно, разве что, с помощью CopyMemory (или с помощью Friend процедуры в классе, возвращающей массив) дублировать массивы в модуль, но это тоже как-то некрасиво и много лишних телодвижений. |
Сообщ.
#6
,
|
|
|
Попробовал CopyMemory, потеря быстродействия более, чем вдвое. Проект прилагаю:
Прикреплённый файлSpdTest2.zip (6,78 Кбайт, скачиваний: 80) |
Сообщ.
#7
,
|
|
|
Цитата Mikle @ А если приёмник так же является одним из источников? Добавить проверку, что аргументы не ссылаются на один и тот же массив. Проще отказаться от такой "экономии", чем хлебать проблемы полной ложкой. |
Сообщ.
#8
,
|
|
|
Нашёл приемлемое решение, без трюков не обошлось, но, вроде бы, получилось безопасно, по крайней мере программа работает в EXE со всеми оптимизациями и в отладчике, выдерживает Stop. Память не течёт.
По сравнению с массивом в модуле теряется где-то 8% быстродействия: Прикреплённый файлSpdTest3.zip (6,5 Кбайт, скачиваний: 69) |