Здравствуйте, Khimik, Вы писали:
K>Здравствуйте, swame, Вы писали:
S>>но ссылка сдохла, положил
S>>https://disk.yandex.ru/d/k4mMp2MCe2c4sQ
K>Спасибо, я включил CheckHeapForCorruption, потом FullDebugMode, запустил мою программу и ошибка не сработала. Возможно у меня не этот тип ошибки. K>Вчера я почистил старые утечки памяти в моей программе и неожиданно ошибка, с которой я начал эту тему, перестала срабатывать. K>Ещё я заметил, что позавчера с Win32 версией тоже срабатывала ошибка range check error на другом функционале программы, т.е. не уверен что проблема именно с преобразованием типов. Но вообще я только сейчас понял, что надо более осторожно переводить код Delphi 7 на Delphi XE 8.
K>Прошу кого-нибудь ответить всё-таки, какие ошибки возможны, если использовать скобки вместо as при приведении типов.
Ну например ты используешь старый недженериковый TList для хранения объектов определенного класса.
Потом поменял тип хранящихся там объектов, например вместо класа теперь там контейнер, включающий этот класс.
НО в каком-то месте кода забыл поправить.
При обращении приводишь объект скобочками , и меняещь значение поля. В этом случае не будет ни ошибок компиляции,
а может и не быть AV, но где-то произвольном месте памяти запортились данные. Такие ошибки сложно находить.
Если же класс из TLISt получаешь через as то сразу возникнет исключение, легко найти ошибку.
Здравствуйте, T4r4sB, Вы писали:
K>>Я вначале перепугался, а потом проверил — и integer и pointer имеют размер 4 байта.
TB>Как в 64 битном режиме указатель может быть 4 байта? TB>Ты не знаешь сколько байт в бите? Или не знаешь что такое 64битный режим?
Я же написал выше что сглупил с постом.
"Ты должен сделать добро из зла, потому что его больше не из чего сделать." Р.П. Уоррен
Здравствуйте, swame, Вы писали:
S>Ну например ты используешь старый недженериковый TList для хранения объектов определенного класса. S>Потом поменял тип хранящихся там объектов, например вместо класа теперь там контейнер, включающий этот класс. S>НО в каком-то месте кода забыл поправить. S>При обращении приводишь объект скобочками , и меняещь значение поля. В этом случае не будет ни ошибок компиляции, S>а может и не быть AV, но где-то произвольном месте памяти запортились данные. Такие ошибки сложно находить. S>Если же класс из TLISt получаешь через as то сразу возникнет исключение, легко найти ошибку.
Это очень интересно, но честно говоря я не знаю что такое контейнер. В то же время я сейчас копаюсь в старом дерьмокоде, написанном 20 лет назад, и там на это наткнулся. Есть tlist, в нём хранятся ссылки на классы. Раньше было:
function TFragmentNode.GetSubItem(index: integer): tfragmentnode;
begin
result:=tfragmentnode(fsubitems[index]);
end;
fsubitems это tlist, tfragmentnode это класс. Попробовал поменять скобку на as и стала срабатывать ошибка Operator not applicable in this operand type.
Сейчас появилась какая-то новая ошибка в этом модуле, не знаю связана она с этим или нет. При чтении содержимого класса tfragmentnode из файла выполняется код
if fwithdata then begin
new(fdata);
loadfragmentfromstream(fdata,stream)
end
При записи соответственно код
if fwithdata then
addfragmenttostream(fdata,stream)
fdata это указатель на рекорд, содержащий два стандартных динамических массива. И сейчас при записи в файл часть данных этого рекорда записываются правильно, но массивы оказываются пустыми. Ещё раз, как выглядит чтение в процедуре LoadFragmentFromStream:
После этого на записи length(fragment^.atoms) возвращается нулевым. Надеюсь я не ступил и не совершил совсем явную ошибку, а тут что-то со спецификой стандартных динамических массивов — я до сих пор не знаю, что они такое и можно ли давать на них ссылки.
"Ты должен сделать добро из зла, потому что его больше не из чего сделать." Р.П. Уоррен
K> function TFragmentNode.GetSubItem(index: integer): tfragmentnode;
K> begin
K> result:=tfragmentnode(fsubitems[index]);
K> end;
K>
K> fsubitems это tlist, tfragmentnode это класс. Попробовал поменять скобку на as и стала срабатывать ошибка Operator not applicable in this operand type.
result:=TObject(fsubitems[index]) as tfragmentnode;
Или замени TList на System.Contnrs.TObjectList или Generics.Collections.TList<tfragmentnode>; Для дженериков приведение вообще не потребуется делать.
K>
result:=TObject(fsubitems[index]) as tfragmentnode;
Можете объяснить, в чём разница с tfragmentnode(fsubitems[index])?
Я ещё раз посмотрел — да если скомпилировать в Win32, то sizeof(pointer) и sizeof(tobject) будут по 4 байта, а если в Win64, то по 8 байт. Даже если тут нет явной ошибки, то явно надо с такими вещами быть осторожнее.
K>>
result:=TObject(fsubitems[index]) as tfragmentnode;
K> Можете объяснить, в чём разница с tfragmentnode(fsubitems[index])?
Если в списке окажется объект другого класса, не являющегося потомком запрашиваемого, то вариант с оператором as вызовет исключение и не даст испортить память. Если есть гарантия, что список содержит именно этот класс, то использовать as не обязательно.
K> Я ещё раз посмотрел — да если скомпилировать в Win32, то sizeof(pointer) и sizeof(tobject) будут по 4 байта, а если в Win64, то по 8 байт. Даже если тут нет явной ошибки, то явно надо с такими вещами быть осторожнее.
В Delphi бъекты являются типами-указателями (см. букварь). Поэтому опасности в подобном преобразовании нет, если есть гарантия, что за указателем объект.
K> R>А inputbuf чему равен?
K> Ну не нулю, это размер строки, записанный в файле.
Тогда проверь чему равна длина дин.массива сразу после того, как делаешь ему SetLength.
Здравствуйте, rudzuk, Вы писали:
K>> Ну не нулю, это размер строки, записанный в файле.
R>Тогда проверь чему равна длина дин.массива сразу после того, как делаешь ему SetLength.
Не нулевой. Вроде объект (ссылка fragment) тот же самый. Я оговорился — не размер строки, а размер этого динмассива.
"Ты должен сделать добро из зла, потому что его больше не из чего сделать." Р.П. Уоррен
Здравствуйте, Khimik, Вы писали:
K> R>Тогда проверь чему равна длина дин.массива сразу после того, как делаешь ему SetLength.
K> Не нулевой. Вроде объект (ссылка fragment) тот же самый. Я оговорился — не размер строки, а размер этого динмассива.
Теперь ищи, где у тебя эта структура диспозится, раз массивы стали пустыми. Нужно ли там вообще возиться с указателями (fdata) из кода не понятно.
Здравствуйте, rudzuk, Вы писали:
K>> R>Тогда проверь чему равна длина дин.массива сразу после того, как делаешь ему SetLength.
K>> Не нулевой. Вроде объект (ссылка fragment) тот же самый. Я оговорился — не размер строки, а размер этого динмассива.
R>Теперь ищи, где у тебя эта структура диспозится, раз массивы стали пустыми. Нужно ли там вообще возиться с указателями (fdata) из кода не понятно.
Да, спасибо, нашёл, это мой древний дерьмокод (иерархический список копируется в другой, потом обратно, при этом элементы tfragmentnode не ассигнятся а копируются как ссылки). Хотя пока не знаю, связана ли эта старая ошибка с проблемой с которой я начал эту тему.
"Ты должен сделать добро из зла, потому что его больше не из чего сделать." Р.П. Уоррен