Передача указателя на TMemoryStream в другую функцию
Вопрос, поднятый в обсуждении, связан с необходимостью передачи указателя на объект TMemoryStream через строковый параметр в другую функцию для последующего использования и освобождения. В примере кода, представленном пользователем, попытка выполнить данную задачу приводит к ошибке доступа.
Проблема
В коде, представленном в контексте, пользователь пытается создать поток TMemoryStream, сохранить в него данные из TMemo, а затем передать указатель на этот поток через строковый параметр в другую функцию для чтения данных. Однако, при попытке чтения данных из потока в второй функции возникает ошибка доступа.
Пример кода (нерабочий)
procedure TForm1.Button1Click(Sender: TObject);
var
Stm: TMemoryStream;
begin
Stm := TMemoryStream.Create;
try
Memo.Lines.SaveToStream(Stm);
Stm.Position := 0;
Memo.Clear;
Edit.Text := IntToStr(Integer(@Stm));
except
Stm.Free;
raise;
end;
end;
procedure TForm1.Button2Click(Sender: TObject);
var
PStm: ^TMemoryStream;
begin
PStm := Pointer(StrToInt(Edit.Text));
try
Memo.Lines.LoadFromStream(PStm^); // Ошибка доступа
finally
PStm^.Free;
end;
end;
Решение проблемы
Проблема заключается в том, что указатель на TMemoryStream, полученный в функции Button2Click, указывает на некорректный адрес в памяти, так как поток Stm освобождается в функции Button1Click в блоке except. Пользователь пытается передать указатель на переменную Stm, но на самом деле ему нужно передать значение указателя, которое Stm хранит.
Правильный код
Чтобы решить проблему, необходимо изменить способ передачи указателя. Вместо того чтобы сохранять адрес переменной Stm, следует сохранять значение указателя, которое Stm представляет. В случае использования Integer для хранения указателя, следует использовать тип NativeInt для обеспечения совместимости с 32-битными и 64-битными системами.
procedure TForm1.Button1Click(Sender: TObject);
var
Stm: TMemoryStream;
begin
Stm := TMemoryStream.Create;
try
Memo.Lines.SaveToStream(Stm);
Stm.Position := 0;
Memo.Clear;
Edit.Text := IntToStr(NativeInt(Stm)); // Используем NativeInt
except
Stm.Free;
raise;
end;
end;
procedure TForm1.Button2Click(Sender: TObject);
var
PStm: ^TMemoryStream;
begin
PStm := Pointer(StrToIntDef(Edit.Text, 0)); // Используем StrToIntDef для безопасности
if PStm <> nil then
try
Memo.Lines.LoadFromStream(PStm^);
finally
PStm^.Free;
end;
end;
Важные замечания
Передача указателя как строки и обратно в числовой формат является небезопасной и может привести к ошибкам, если между вызовами функций Button1Click и Button2Click происходит выделение памяти в том же сегменте.
Более безопасным решением будет передача указателя напрямую, без использования строкового представления.
В коде выше использован StrToIntDef для предотвращения ошибок при преобразовании строки в число, если строка не может быть преобразована, возвращается значение по умолчанию 0.
Этот подход позволяет безопасно использовать и освобождать TMemoryStream после его передачи в другую функцию.
Контекст описывает проблему в программировании на Delphi, связанную с неправильной передачей указателя на объект `TMemoryStream` между функциями через строковый параметр, что приводит к ошибке доступа.
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.