Непонятки с массивами строк - страница 3

 
При распределении строки добавляется ещё 15 лишних байт. Строка может быть переприсвоена. Если новая строка помещается в эти старые n байт + 15 байт резерва, то перераспределения не происходит. Если же не помещается, то производится перераспределение с добавлением к новой длине 15 байт.
 
elritmo:

Как же вы записываете тогда в поле len максимальную длину строки? И если вы выбираете размер буфера максимальный то и размер строки тоже видимо ограничивается максимальным значением строки. Надо глянуть в доке по MQL4. Но если такого ограничения нет то максимальный размер видимо указывается как MAX_INT

Максимальный размер буфера модифицируется в рантайме, когда происходят операции со строками. Ограничение выставляется экономно, но с запасом.
 
То есть в рантайме когда в эксперте присваивается новое значение строке, то терминал анализирует её длину и если new string length > (old string length + 15 byte) то вы делаете буфер равным (new string length + 15 byte). Но это происходит только в эксперте, если записываем новую строку, а если в длл то длина новой строки должна быть не больше буфера + 15 на момент её передачи в функцию длл. Всё это понял.
Ещё хотел поинтересоваться. Насущный вопрос. Я делаю в эксперте импорт функций и думаю что она загружается динамически (в отладчике длл это заметил).
Но при удалении эксперта с чарта (на одном чарте только разместил эксперта) и при удалении его с чарта длл не освобождается иногда и остаётся занятой терминалом пока терминал не закрою. Хотел узнать при удалении терминала с чарат и если длл была загружена динамически то вызывается ли FreeLibrary?
 

FreeLibrary вызывается при выгрузке эксперта, вызвавшего функцию из этой библиотеки.

 
Хм тогда очень странно почему иногда файл библиотеки не освобождался терминалом для того чтобы его заменить новой версией. Ещё потестирую с этим может быть проблема больше не возникет. Или она возникает когда запускаю отладку длл или дебаг версию длл размещаю в папку libraries в терминале.
Положу релиз версию в эту папку и потестирую на освобождения длл для записи новой версией.
 
elritmo:
Хм тогда очень странно почему иногда файл библиотеки не освобождался терминалом для того чтобы его заменить новой версией. Ещё потестирую с этим может быть проблема больше не возникет. Или она возникает когда запускаю отладку длл или дебаг версию длл размещаю в папку libraries в терминале.
Положу релиз версию в эту папку и потестирую на освобождения длл для записи новой версией.
Может библиотека еще где-то использовалась? Тестер, другие окна и тд.
 
Renat, в вашем примере, функция GetStringValue описана как
MT4_EXPFUNC char* __stdcall GetStringValue(char *spar)
(т.е. возвращает pchar)

Вызов ее выполняется как
string sret;
sret=GetStringValue("some string");

Посему возникают вопросы:

Что произодет со структурой MqlStr?
Т.е. в data записывается возвращаемый pchar, а что произойдет с полем len, туда запишется длина вернувшейся строки (а как быть со строками в сегменте .data)?
Что произойдет, если в эту строку в дальнейшем будет запись строки бОльшего размера - должно ж ведь произойти реаллоцирование памяти, а если у вас собственный memory manager, то ведь будут проблемы, или память выделяется средствами win api?
Будет ли освобождена память вернувшейся строки, когда, и через какую функцию?

Я это все к тому, что я могу выделить память под строку разными способами - это и делфевский GetMem, который использует собственный ММ, и api-шные VirtualAlloc/GlobalAlloc/HeapAlloc, и вернуть ссылку на статические данные как pchar, и как вы ее потом собираетесь освобождать?
Хотелось бы, чтобы вы озвучили механизм как надо делать (о чем вас просят уже довольно долго ;), но тема до сих пор не раскрыта).
В вашем примере, внутри GetStringValue, возвращаемая строка не аллоцируется (поэтому пример можно назвать неудачным).
 
Мы просто скопируем строку из Вашего буфера в _свою_ строку, с выделением в _своем_ пуле. А потом Ваша строка нас не интересует. То есть, если Вы дадите нам динамическую (через выделение памяти) строку, а потом сами не позаботитесь об ее отслеживании и удалении, то получите серьезнейшую утечку памяти.

Что рекомендуется делать:
  • не возвращать никаких строк в MQL4, а заполнять строки, переданные в параметрах
  • если возвращать, то выдавать ссылки на статические буферы (не в стеке!) или из своего собственного контролируемого пула с четким пониманием, что любая выданная "наверх" строка становится неконтролируемой до конца работы.

Что еще важно - если пишете в DLL функции, которые вызываются миллионы раз (а это происходит в тестере), то минимизируйте количество перевыделений памяти. Никаких массовых new/delete на каждом вызове. Не фрагментируйте память процесса своими массовыми перевыделениями. Мы в разы ускорили тестер и MQL4, избавившись от множественных перевыделений памяти.

ps: забудьте запись/модификацию параметра len - Вас вообще не должен он волновать. Вы можете только читать и все. Что туда писать решает среда выполнения MQL4.
 
Спасибо, Renat, после трех страниц топа я все таки выжал из вас инфу :D

Хотя из всего этого следует один неутешительный вывод - свой pchar вернуть нельзя (а если и вернуть, то как его потом освобождать?), можно только переписывать буфер переданной строки (что вы и описали в ваших рекомендациях).

Может вам имеет смысл написать статью про весь этот механизм?
А то данный топ потеряется в архивах, а вопросы останутся...

з.ы. Хотелось бы, чтобы в mql4 была функция задания длины строки (типа SetLength), по крайней мере в хелпе не нашел, т.к. сейчас приходится формировать ее в цикле типа
for (int i=1; i<=MaxStringLength; i++) MaxString = MaxString + " ";

С учетом того, что вы озвучили, что реалллокейт строки происходит по 15 символов - можно оптимизировать, но это все равно как то через задницу - мой мозг оптимизатора (в чем мы с вами похожи) такой вариант воспринимает с трудом :)
Причина обращения: