Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Основная";
Текущий архив: 2004.05.30;
Скачать: [xml.tar.bz2];

Вниз

Как узнать выделена память под указатель или нет?   Найти похожие ветки 

 
Bless ©   (2004-05-13 11:54) [0]

сабж.

P.S.
Наверное, надо бы этот вопрос в основную задать, но у меня что-то
при попытке это сделать
500 Internal Server Error выскакивает


 
Соловьев ©   (2004-05-13 12:08) [1]

проверь на nil


 
Тимохов ©   (2004-05-13 12:12) [2]

Автору:

Теоретически можно - покопаться в getmem.inc, сделать свой манагер памяти, который будет говорить, если ли память под указателем.

В умолчательной реализации манагера памяти дельфи этого сделать нельзя.


> Соловьев ©   (13.05.04 12:08) [1]

И что - это даст гарантию, что под указатель выделена память?


 
Соловьев ©   (2004-05-13 12:16) [3]


> Тимохов ©   (13.05.04 12:12) [2]

не знаю :)
я по аналогии в С :)
там я делаю проверку на NULL


 
Тимохов ©   (2004-05-13 12:28) [4]

я тут подумал, что все как обычно - не совсем понятен вопрос:
1. Вариант 1 - "понять" после вызова getmem, например. Ответ - в случае ошибки (нехватки памяти) никто вам понимать времени не даcт - просто будет возбуждено исключение.
2. Вариант 2 - по неизвестно откуда взявшемуся указателю понять, есть ли под ним выделенная память. Ответ - см мой ответ выше.


 
Danilka ©   (2004-05-13 12:34) [5]

А зачем это может понадобиться? Просто интересно. Разве что, для: [4] Тимохов ©   (13.05.04 12:28), вариант 2, но сразу встает вопрос:
Откуда в своей программе может взяться неизвестно откуда появившийся указатель?

:))


 
Тимохов ©   (2004-05-13 12:38) [6]

вот например - указатель призрак.
var
  o, o1, o2: tobject;
bagin
  o := tmyobject.create();
  o1 := o;
  o2 := o;
  ........
  .......
  o1.free();
  ......
  .....
  как тут понять жив ли o2?
end;


 
Danilka ©   (2004-05-13 12:40) [7]

[6] Тимохов ©   (13.05.04 12:38)
кстати, в этом примере не понять даже жив или нет o1, вот если-бы FreeAndNil..


 
han_malign ©   (2004-05-13 13:58) [8]

ValidPtr = (p<>nil)and(Integer(Pointer(Integer(p)-4)^)and 3 = 2);
только работать будет только для указателей выделеных через GetMem/New
строки, динамические массивы, классы  - там другую информацию держат (длина, длина, адрес VMT - соответсвенно, и отнимать надо -12, -12(RefCount*4/Length*4), -8(@VMT*4) - но это нужно проверять, возможно и через другой механизм работает), для интерфейсов вообще не знаю

с флагами можно еще помудрить
 cThisUsedFlag = 2;
 cPrevFreeFlag = 1;
 cFillerFlag   = Integer($80000000);
 cFlags        = cThisUsedFlag or cPrevFreeFlag or cFillerFlag;


 
han_malign ©   (2004-05-13 14:01) [9]

для классов похоже наврал - адрес VMT, это просто неявное поле(по нулевому смещению, а не минус 4) - хотя тоже надо проверять


 
Тимохов ©   (2004-05-13 14:16) [10]


> han_malign ©   (13.05.04 13:58) [8]

Все это очень хорошо :)))
Но все-равно результат не 100% гаринтирован.
Так писать только баги невылавливаемые плодить.

Единственный гарантированный (похоже :))) способ - написать свой манагер памяти.


 
Verg ©   (2004-05-13 14:21) [11]


> Тимохов ©   (13.05.04 14:16)
> Единственный гарантированный (похоже :))) способ - написать
> свой манагер памяти.


А че, заняться больше нечем? ;)


 
Тимохов ©   (2004-05-13 14:23) [12]


> А че, заняться больше нечем? ;)

Мне то как раз есть.
Сами заметте, что вопросы как узнать по указателю выделена ли под ним память возникают почти каждый день (точно 3 было на этой неделе).

:))))


 
Verg ©   (2004-05-13 14:56) [13]

Если такие вопросы начинают возникать - сто пудов, чел пошел не той дорогой. Заблудился.


 
Bless ©   (2004-05-13 14:56) [14]

>Откуда в своей программе может взяться неизвестно откуда
>появившийся указатель?

Память, выделенная под объект могла быть освобождена после некоторых действий пользователя.

>А зачем это может понадобиться?

А бог его знает :)
Вопрос навеян любопытством.
Просто нашел в старом куске кода фрагмент

  if DataModule2.FindComponent("FrmAdd")=nil then
     FrmAdd:=TFrmAdd.Create(self);
  FrmAdd.show;

Стало интересно, почему я не написал просто

  if frmAdd=nil FrmAdd:=TFrmAdd.Create(self);
  FrmAdd.show;

Посмотрел хелп, узнал (точнее, вспомнил), что с nil все немножко не так как я думал.

Можно, конечно, вместо
 
 obj.free

писать

 obj.free;
 obj:=nil;

и дальше

if obj=nil then ...

Но я подумал, что есть способ поэлегантнее, вот и спросил.


 
Algol   (2004-05-13 15:09) [15]


> могла быть освобождена после некоторых действий пользователя.


А я-то по наивности думал, что с памятью работают только программы.. Ан нет, оказывается и пользователь усилием мысли может освобождать память :))


 
Danilka ©   (2004-05-13 15:12) [16]


> Можно, конечно, вместо
>  
>  obj.free


Для этого в модуле Sysutils и есть процедура: FreeAndNil


 
Тимохов ©   (2004-05-13 15:15) [17]

Автору.
Согласен с Verg - не той дорогой идете.
Если хотите знать больше про память, что:
1. Читайте Рихтера - раздел "Управление памятью" - память в windows.
2. Читайте ссылку - http://rsdn.ru/article/Delphi/memmanager.xml - манагер памяти в delphi.

Думаю вопросов не будет...


 
WebErr ©   (2004-05-13 16:12) [18]


> я по аналогии в С :)
> там я делаю проверку на NULL

Там работа с памятью реализованно точно так же! :))))
В С/С++ просто проверка на NULL не даст нужного результата после delete []ptr, delete ptr, free(ptr).
Так что - это бред! :))))
По сабжу у меня только комментарий наподобие:
"А Вам это надо?"
На самом деле, разве можно (вернее нужно ли?) котролировать каждую переменную типа указатель?! ;)


 
default ©   (2004-05-13 19:32) [19]

наверно, самое примитивное что можно придумать, но автора возможно впечатлит..."поставить" свои ф-ии GetMem и FreeMem
первая будет после успешного выдел-ия памяти ориг-ым GetMem-ом
увел-ать размер дин-ого массива на 1 и писать в этом элемент число которое лежит в ссылочной перем-ой, после ориг-ого FreeMem-а удалять соотв-ий элемент(или через односвязные списки сделать...)или TList
соотв-но чтобы проверить дейст-ен указ-ль или нет надо проверить его наличие в указанном массиве, списке, TList-е или где ещё...


 
Zz_   (2004-05-13 19:52) [20]

Стандартный подход - завернуть указатель в оболочку SmartPtr
но не для паскалля


 
default ©   (2004-05-13 21:59) [21]


unit Unit1;

interface

uses
 Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
 Dialogs, StdCtrls;

type
 TForm1 = class(TForm)
   Button1: TButton;
   procedure Button1Click(Sender: TObject);
 private
   { Private declarations }
 public
   { Public declarations }
 end;

var
 Form1: TForm1;

implementation

{$R *.dfm}

var
PointerList: TList;
OldMemMgr: TMemoryManager;
O: TObject;

function NewGetMem(Size: Integer): Pointer; forward;
function NewFreeMem(P: Pointer): Integer; forward;
function NewReallocMem(P: Pointer; Size: Integer): Pointer; forward;

const
NewMemMgr: TMemoryManager = (GetMem: NewGetMem;
                             FreeMem: NewFreeMem;
                             ReallocMem: NewReallocMem);

function NewGetMem(Size: Integer): Pointer;
begin
Result := OldMemMgr.GetMem(Size);
SetMemoryManager(OldMemMgr); // для избежания
if Result <> nil then PointerList.Add(Result);
SetMemoryManager(NewMemMgr) // рекурсии
end;

function NewFreeMem(P: Pointer): Integer;
begin
Result := OldMemMgr.FreeMem(P);
if Result = 0 then PointerList.Remove(P)
end;

function NewReallocMem(P: Pointer; Size: Integer): Pointer;
begin
Result := OldMemMgr.ReallocMem(P, Size);
if Result <> nil then if P <> Result then
PointerList[PointerList.IndexOf(P)] := Result
end;

procedure BeginControlPointer;
begin
PointerList := TList.Create;
GetMemoryManager(OldMemMgr);
SetMemoryManager(NewMemMgr)
end;

procedure EndControlPointer;
begin
PointerList.Destroy;
SetMemoryManager(OldMemMgr)
end;

function ValidPointer(P: Pointer): Boolean;
begin
Result := PointerList.IndexOf(P) <> -1
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
BeginControlPointer;
// теперь мы можем смело проверить любой указатель на актуальность
O := TObject.Create;
O.Free;
if ValidPointer(O) then Caption := "Valid Pointer"
else Caption := "Invalid Pointer";
EndControlPointer
end;

end.

можно закинуть в фак...


 
default ©   (2004-05-13 23:06) [22]

вместо вот этого
function NewGetMem(Size: Integer): Pointer;
begin
Result := OldMemMgr.GetMem(Size);
SetMemoryManager(OldMemMgr); // для избежания
if Result <> nil then PointerList.Add(Result);
SetMemoryManager(NewMemMgr) // рекурсии
end;
лучше это
function NewGetMem(Size: Integer): Pointer;
begin
Result := OldMemMgr.GetMem(Size);
if Result <> nil then begin
SetMemoryManager(OldMemMgr); // для избежания
PointerList.Add(Result);
SetMemoryManager(NewMemMgr) // рекурсии
end
end;


 
Mim1 ©   (2004-05-14 05:50) [23]

Народ а что дает мне замена менеджера памяти? Ведь знать что по ссылке выделена память недостаточно. Нужно, еще, знать выделена ли она мной. То есть такой примерный код
if validatepointer(mimstringlist) and (mimstringlist is tstringlist) then
 mimstringlist.add("mim");

применять я не стану, даже если validatepointer работает правильно, по тому что слычайно ссылка может указывать не на мой обьект а на чей нибудь другой.


 
evvcom ©   (2004-05-14 08:17) [24]

Бред какой развели! Выделил память - присвоил указателю. Где надо, проверил на nil. Память вернул - обнулил указатель. Все это делать всегда с "первичным" указателем. Любые локальные указатели ("вторичные") использовать очень аккуратно и продуманно. И при соблюдении этих правил нормально работает проверка на nil. Если вдруг выскочет AV - значит где-то что-то упустил. А появление "неизвестно откуда появившихся указателей" - логическая ошибка программы, которую надо устранять не написанием своих менеджеров памяти, а анализом и отладкой места, отвечающего за выделение/освобождение памяти под свои указатели.


 
default ©   (2004-05-14 10:26) [25]

Mim1 ©   (14.05.04 05:50) [23]
един-ое условие и оно естественно(память должна быть выделена через GetMem, ReallocMem и после вызова BeginControlPointer;


 
default ©   (2004-05-14 10:37) [26]

evvcom ©   (14.05.04 08:17) [24]
это ж как вариант...автор поставил вопрос ему ответили
естественно Вы правы, если бы это было не так Borland поселило бы ф-ию подобную ValidPointer-у в модуль System


 
Игорь Шевченко ©   (2004-05-14 10:41) [27]


> Бред какой развели! Выделил память - присвоил указателю.
> Где надо, проверил на nil. Память вернул - обнулил указатель.


А вот есть такие Smart Pointers :) Которые все делают самостоятельно, без участия программиста. Зря так категорично, область вполне заслуживает внимания.


 
Danilka ©   (2004-05-14 10:46) [28]

[27] Игорь Шевченко ©   (14.05.04 10:41)
А где их применение оправдано? В смысле, нельзя без них обойтись обычными средствами? Честно говоря, не могу себе представить, вот и интересно.


 
Игорь Шевченко ©   (2004-05-14 11:28) [29]

Danilka ©   (14.05.04 10:46)


> А где их применение оправдано? В смысле, нельзя без них
> обойтись обычными средствами? Честно говоря, не могу себе
> представить, вот и интересно.


Дык, все сборщики мусора так работают. Например, в Java, в C#, в SmallTalk


 
evvcom ©   (2004-05-14 11:38) [30]


> А вот есть такие Smart Pointers :) Которые все делают самостоятельно,
> без участия программиста.

Пизнаюсь, раньше не встречал этого понятия. Нашел статью о них http://www.gotw.ca/gotw/062.htm. Насколько я понял, все это облачается в класс для более удобной работы. Не паришься больше с выделением/освобождением памяти, все это берет на себя класс. Я часто так и делаю, пишу все нудные операции в классе и дальше голову не забиваю, это естественно, просто не знал, что такой подход уже имеет свое название, ну это не важно.

> Зря так категорично

Возможно. И тем не менее, если человек не может нормально работать с указателями, то о каком собственном менеджере памяти можно говорить?


 
Игорь Шевченко ©   (2004-05-14 11:40) [31]


> И тем не менее, если человек не может нормально работать
> с указателями, то о каком собственном менеджере памяти можно
> говорить?


С этим утверждением спорить трудно :)


 
evvcom ©   (2004-05-14 11:41) [32]

Или все же нет?

private:
 auto_ptr<Y> y_;

auto_ptr - это уже конструкция языка?


 
Danilka ©   (2004-05-14 11:54) [33]

[29] Игорь Шевченко ©   (14.05.04 11:28)
Понятно где могут пригодиться Smart Pointers, но непонятно для чего нужно узнавать: выделена память под обычный указатель или нет.


 
Игорь Шевченко ©   (2004-05-14 11:59) [34]


> непонятно для чего нужно узнавать: выделена память под обычный
> указатель или нет.


Мне сложно придумать пример, где бы это могло быть реально оправдано, в подобных случаях я обычно счетчиком ссылок обхожусь, например, при реализации синглтонов.


 
Тимохов ©   (2004-05-14 12:17) [35]


> evvcom ©   (14.05.04 08:17) [24]

почему вы так категоричны - мы тут причем, никто ничего не разводил.
У автора был вопрос - ему ответили. Как он будет этим пользоваться его дело.


 
evvcom ©   (2004-05-14 17:06) [36]


> Тимохов ©   (14.05.04 12:17) [35]

Просто я не вижу смысла писать свой мем-менеджер. Причем тем, кто на это способен, уже не надо объяснять, что существует такая возможность. И чтобы браться за такое, должна быть веская причина, ну или если совсем делать нечего... Вполне достаточно написать простенький класс, управляющий пользовательскими данными, конкретными структурами (выделение, освобождение памяти).


 
Тимохов ©   (2004-05-14 17:09) [37]


> evvcom ©   (14.05.04 17:06) [36]

Полность с вам согласен.

Другое дело, что автор задал вопрос - ему ответили.
Тоже полезно знать для общего развития.

Резьюм:
Следить самому за указателями надо, а не полагаться на манагер памяти.


 
WebErr ©   (2004-05-14 17:21) [38]


> Игорь Шевченко ©   (14.05.04 10:41) [27]

Дык, SmartPtrs это одно дело, а просто Pointers - это другое. :)
Мне просто интересно, зачем автору понадобилось узнавать, выделена ли память под указатель.
Признаюсь, после нескольких часов раздумий эта тема меня понемногу захватила.
Действительно, неплохо было бы, если б можно было отсылать запросы типа "сколько указателей смотрят на данный блок [динамически выделенной] памяти" или "выделена ли память под данный указатель [сколько?]".
Это всё очень и очень интересно!!! :)


 
Danilka ©   (2004-05-14 17:27) [39]

[38] WebErr ©   (14.05.04 17:21)
см: [34] Игорь Шевченко ©   (14.05.04 11:59)
:))
или почитай, например, как работает в Дельфи AnsiString.


 
Danilka ©   (2004-05-14 17:31) [40]

[38] WebErr ©   (14.05.04 17:21)
хотя, все может быть сложнее..



Страницы: 1 2 вся ветка

Форум: "Основная";
Текущий архив: 2004.05.30;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.56 MB
Время: 0.035 c
14-1084515269
Rule
2004-05-14 10:14
2004.05.30
Направте на правильный путь решения проблеммы..


14-1083159353
SeriousSam
2004-04-28 17:35
2004.05.30
Помогите выбрать комп


7-1081952346
DeMoN_Astra
2004-04-14 18:19
2004.05.30
Запуск приложения до авторизации


3-1084283277
nova
2004-05-11 17:47
2004.05.30
Список серваков sql server в delphi


3-1084273128
stud
2004-05-11 14:58
2004.05.30
кто работал с квантумгрид





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский