Форум: "Основная";
Текущий архив: 2003.05.29;
Скачать: [xml.tar.bz2];
ВнизПара вопросов про ObjectPascal Найти похожие ветки
← →
Maksim Realov (2003-05-16 18:39) [0]Здравствуйте! Хотел спросить про структуры и ссылки на них.
Если я объявляю структуру так:
type
TMyStruct = record
i: integer;
s: string;
end;
а потом использую её в таком виде:
procedure TForm1.Button1Click(Sender.TObject);
var
MyStruct: TMyStruct;
begin
MyStruct.i:= 5;
end;
То при таком способе объявления переменной MyStuct память под неё резервируется при запуске приложения и освобождается по его закрытии. Так?
А если я объявляю так:
type
PMyStruct = ^TMyStruct;
TMyStruct = record
i: integer;
s: string;
end;
procedure TForm1.Button1Click(Sender.TObject);
var
MyStruct: PMyStruct;
begin
New(MyStruct);
MyStruct^.i:= 5;
Dispose(MyStruct);
end;
То при таком способе определения память выделяется и освобождается динамически.
Но ведь MyStruct объявленная как TMyStruct тоже является фактически завуалированным указателем на туже структуру.
Ведь если сделать так:
type
TMyStruct = record
i: integer;
s: string;
end;
procedure TForm1.Button1Click(Sender.TObject);
var
M1, M2: TMyStruct;
begin
M1.i:= 5;
M2.i:= 7;
end;
В таком случае М1 и М2 ссылаются на разные экземпляры структур. И под эти две переменные распределяется автоматически память.
Мои рассуждения верны?
И ещё вопрос – почему после уничтожения объекта (метод Free) ссылка на него не обнуляется?
← →
Романов Р.В. (2003-05-16 18:51) [1]
> procedure TForm1.Button1Click(Sender.TObject);
> var
> MyStruct: TMyStruct;
> begin
> MyStruct.i:= 5;
> end;
Переменная MyStruct локальная по этому память под нее (грубо говоря) выделяется только при выполнении этой процедуры и после выхода из нее освобождается.
> И ещё вопрос – почему после уничтожения объекта (метод Free)
> ссылка на него не обнуляется?
На объект может быть куча сслок. Их все нужно обнулять? Используй FreeAndNil для обнуления ссылки и освобождения памяти
← →
Юрий Федоров (2003-05-16 18:52) [2]>procedure TForm1.Button1Click(Sender.TObject);
>var
> MyStruct: TMyStruct;
>begin
> MyStruct.i:= 5;
>end;
>То при таком способе объявления переменной MyStuct память под >неё резервируется при запуске приложения и освобождается по его >закрытии. Так?
Память резервируется при входе в процедуру, и освобождается при выходе из нее
>>Но ведь MyStruct объявленная как TMyStruct тоже является >>фактически завуалированным указателем на туже структуру.
MyStruct НЕ является указателем
>>И ещё вопрос – почему после уничтожения объекта (метод Free) >>ссылка на него не обнуляется?
Потому что объект ничего не знает о ссылке на него, ссылок кстати может быть несколько
← →
Skier (2003-05-16 18:52) [3]>Maksim Realov
1)
procedure TForm1.Button1Click(Sender.TObject);
var
MyStruct: TMyStruct;
begin
MyStruct.i:= 5;
end;
-Память под переменную MyStruct (8 байт) выделяется при входе
в процедуру(метод)
-Освобождается при выходе из процедуры(метода)
- Всё делает компилятор, тебе не надо здесь заботится о памяти
2)
procedure TForm1.Button1Click(Sender.TObject);
var
MyStruct: PMyStruct;
begin
New(MyStruct);
MyStruct^.i:= 5;
Dispose(MyStruct);
end;
- MyStruct это указатель на запись (4 байта)
- память под MyStruct (4 байта) выделяется при входе
в процедуру(метод) и освобожнается при выходе.
- память же под то на что собственно указавает MyStruct тебе
нужно выделять и освобождать самому.
3)
> И ещё вопрос – почему после уничтожения объекта (метод Free)
> ссылка на него не обнуляется?
Освобождается память которую занимает экземпляр класса, ссылка
на него это всего лишь типизированный указатель (4 байта) ( "похожий" на MyStruct: PMyStruct;) )
Если нужно обнулять и ссылку, то используй FreeAndNil(...)
← →
Юрий Федоров (2003-05-16 18:52) [4]Не успел :-)
← →
MBo (2003-05-16 18:53) [5]1)Под локальные переменные память выделяется в стеке при входе в процедуру и освобождается при выходе.
2) Начиная с D5 появилась процедура FreeAndNil.
Можно и руками обNil-ять.
А не сделано авт. обнуление, поскольку ссылок на объект может быть несколько в разных местах, и автоматически все их обнулить нельзя.
← →
MBo (2003-05-16 18:54) [6];))
← →
Serginio (2003-05-16 19:01) [7]Пусть войдет в привычку
New(MyStruct); FillChar(MyStruct^,SizeOf(TMyStruct),0);
// или Pointer(MyStruct.s):=nil;
MyStruct^.i:= 5;//
//MyStruct.i:= 5; без разницы
MyStruct.s:="xxxxxxxxxxx";// можешь получить инвалид поинтер операцию если не обнулишь структуру
← →
Skier (2003-05-16 19:05) [8]
> MyStruct.s:="xxxxxxxxxxx";// можешь получить инвалид поинтер
> операцию если не обнулишь
Это...вряд ли. (С) тов. Сухов
← →
Maksim Realov (2003-05-16 19:15) [9]так зачем же тогда вообще заморачиваться с указателями на структуру, если можно просто:
MyStr: TMyStr;
и всё???
Зачем вводить PMyStr = ^TMyStr ???
← →
Skier (2003-05-16 19:18) [10]>Maksim Realov (16.05.03 19:15)
А затем, что при выходе из метода у тебя у же не будет
MyStr, а сие не всегда нужно, задачи-то разные бывают...
← →
Maksim Realov (2003-05-16 19:22) [11]Тогда я вообще не понимаю в чём разница использования MyStr: TMyStr; и MyStr: PMyStr; кроме незначительной разницы в распределеии и освобождении памяти (в первом случае это делает компилятор, во втором - программер)???
← →
Serginio (2003-05-16 19:24) [12]>>Skier © (16.05.03 19:05)
При New структура не инициируется нулями и на месте s будет не nil компилятор при виде такого безобразия попробует удалить данную строку за не нужность. Если не веришь мне вот борландовский код TstringList
procedure TStringList.InsertItem(Index: Integer; const S: string; AObject: TObject);
begin
Changing;
if FCount = FCapacity then Grow;
if Index < FCount then
System.Move(FList^[Index], FList^[Index + 1],
(FCount - Index) * SizeOf(TStringItem));
with FList^[Index] do
begin
Pointer(FString) := nil;
FObject := AObject;
FString := S;
end;
Inc(FCount);
Changed;
end;
← →
Skier (2003-05-16 19:27) [13]>Maksim Realov (16.05.03 19:22)
> кроме незначительной разницы в распределеии и освобождении
> памяти
В контексте твоего вопроса эта разница не незначительной,
а огромна !
И я так понимаю, что ты ещё ни разу не использовал с своих
проектах дин. структур и работу с ними, поэтому, (из-за того что
тебе не понятна область применения) ты не улавливаешь всей
разницы.
← →
Serginio (2003-05-16 19:35) [14]>>>Maksim Realov (16.05.03 19:22)
Обязательно найди книжечку Вирта про связные спискы. А также при работе с не сртруктурированной памятью распределенной память
Для проимера у тебя есть ссылка на кусок памяти p:Pchar;
If PInteger(p)=3 Then
inc(p,sizeOf(Integer);
If PMyStruct(p).i=5 Then
А вообще можно миллион примеров привести, особенно работая с АПИ где все передается по указателям.
Например при вызове процедуры типа
Procedure (Var t:TMyStruct); аналогична
Procedure (t:PMyStruct) в С применяется больше такой подход.
← →
Maksim Realov (2003-05-16 19:35) [15]>> Skier © (16.05.03 19:27):
Вот я и хочу уловить разницу, что бы делать всё правильно и осмысленно!
← →
Maksim Realov (2003-05-16 19:38) [16]Вы меня извините ребята за тупость, но понять не могу: при t:TMyStruct в переменной t лежит указатель на экземпляр структуры!
Книги я читаю конечно и читать буду - без этого никуда!
← →
Skier (2003-05-16 19:40) [17]>Serginio (16.05.03 19:24)
for ii := 0 to 100000 do begin
New(MyStruct);
MyStruct^.s := "Hello, world !";
Dispose(MyStruct);
end; //for
AV получишь хоть раз ?
← →
Serginio (2003-05-16 19:51) [18]Все может быть значит повезло но, New не инициализирут память 0.
И поверь мне натыкался не раз.
← →
Serginio (2003-05-16 20:00) [19]>>Maksim Realov
Нет при выделении памяти под Т компилятор запоминает ее адрес сам. При динамическом выделении памяти в куче ответственность за адресс структуры лежит на прогрммисте. Можно запомнить адрес структуры например
t:TMyStruct;
Pt,pt2:PMyStruct ;
PT:=@t;
pt.i:=5;// t=5;
new(pt2);
pt:=pt2;
pt.i:=3;// pt2^3;
и работать со структурой по указателю. Это особенно важно когда не знаешь где эта переменная находится в стеке или в куче.
← →
Serginio (2003-05-16 20:14) [20]Skier © (16.05.03 19:40)
Кстати скорее всего я не прав New инициализирует структуру, а Dispose уничтожает все правильно. Все мои посты относятся к GetMem и другим типам не структурированного выделения памяти.Честно говоря уже и не помню когда работал с New и Dispose.
← →
Skier (2003-05-16 20:20) [21]>Serginio (16.05.03 20:14)
> New инициализирует структуру, а Dispose уничтожает все правильно
Совершенно правильно.
← →
Serginio (2003-05-16 20:40) [22]Еще раз извиняюсь за свое невежество (Вернее память). Был не прав. В основном пользуюсь хипами, что очень удобно при одновременном уничтожении памяти, а вместо всякого рода листов динамические массивы лучше всего.
← →
Skier (2003-05-16 20:45) [23]>Serginio (16.05.03 20:40)
Nobody"s perfect. :)
← →
Maksim Realov (2003-05-20 10:42) [24]Так что лучше использовать для выделения памяти под структуру: New/Dispose или GetMem/FreeMem?
А если не выделить память под структуру и попытаться произвести запись в её поля, то всегда будет AV?
← →
Skier (2003-05-20 10:45) [25]>Maksim Realov (20.05.03 10:42)
1)Для твоего случая New/Dispose
2)Трудно сказать всегда или нет, может разок другой повезёт,
но это совершенно не значит что под динамические
структуры не надо выделять память.
← →
Digitman (2003-05-20 11:10) [26]
> если не выделить память под структуру и попытаться произвести
> запись в её поля, то всегда будет AV?
нет, не всегда.
связано это с выравниванием блоков аллокируемой памяти на границу, специфичную для конкретного менеджера памяти, а так же со странично-ориентированным управлением вирт.памятью на уровне ОС
скажем, запросил ты у менеджера памяти 1 байт
var
MyArray: PChar;
..
GetMem(MyArray, 1);
и теперь обращаешься к памяти явно за пределами массива
MyArray[3] := #0; // исключения в случае с менеджером от Борланда никогда не возникнет !
MyArray[15] := #0; // исключения в случае с менеджером от MS в (составе, например, MSVCRT) никогда не возникнет !
MyArray[4] := #0; // вероятность исключения в случае с менеджером от Борланда существует ! все зависит от того, как "ляжет" страница)
Страницы: 1 вся ветка
Форум: "Основная";
Текущий архив: 2003.05.29;
Скачать: [xml.tar.bz2];
Память: 0.51 MB
Время: 0.008 c