валиден указател

23 отговора 940 прегледа
#1

валиден указател

как мога да разбера дали даден указател е валиден? имам предвид нещо от рода:


int *a,*b;
a=new int;
b=new int;
delete a;
ASSERT(!IsValidPointer(a));
ASSERT(IsValidPointer(b));

забелязал съм че когато трия вече изтрит указател, хийпа гърми, а ако имаше начин да се провери, предполагам нямаше да гърми, защото щеше да се усети че му пробутвам за изтриване невалиден указател.

Отговор
в отговор на zaphod #2

Re: валиден указател

Доколкото съм запознат много добра практика е да се дефинира някакъв макрос SAFE_DELETE, който освен delete на указателя да го прави и равен на NULL. Идеята е вместо обикновения delete да викаш въпросния макрос и работата е готова. IsValidPointer ще проверява само дали указателят е NULL.

Отговор
в отговор на Lupi #3

мен ми трябва за друго

трябва ми за случай когато на тоя указател има много направени копия. по принцип такъв проблем трябва да се реши организационно - да се погрижа копията да се знаят, обаче е много сложно. пробвах дали четенето и записа в изтрит указател могат да се хванат със try catch, обаче не става.

Отговор
в отговор на Lupi #4

Re: валиден указател

...и понеже в C++ макросите се водят evil:

template <class T> void safe_delete(T*& p) { delete p; p = 0; }

а който не го мързи може и така да го направи:

template <class T> void safe_delete(T*& p) { if (p) { delete p; p = 0; } }

...ама няма смисъл, щото Светият Стандарт казва, че delete на нулев pointer е разрешена операция и не прави нищо.

Отговор
в отговор на zaphod #5

Re: мен ми трябва за друго

В твоя случай май по-скоро трябва да се ориентираш към smart pointers или reference counting.

Има и друга алтернатива, но не е много добра, и върши работа само за поинтери към твои си структури и класове, върху които имаш контрол. За int* няма да стане. Идеята е да вкараш във class/struct-а си някое поле със специална стойност, например unsigned magic = 0xABEDEEBA; В конструктора на класа/структурата го сетваш със специалната стойност, а в деструктора го нулираш. Съответно, ако искаш да провериш дали поинтера сочи към валиден обект, просто проверяваш дали е ненулев и дали съответното поле има въпросната специална стойност. Разбира се, тоя метод може да се издъни лесно при неправилна употреба - например ако оставиш поинтера да сочи някъде съвсем на майната си, програмата ти сигурно ще гръмне с page fault. И изобщо си е bad practice, казвам го само за пълнота.

Редактирано от Pesho® на

Отговор
в отговор на zaphod #6

Re: валиден указател

pishi bez poiteri kato mene i nema da imash griji

Отговор
в отговор на Pesho® #7

така няма да стане

защото когато изтриеш обекта хийпа записва някаква информация отгоре му и полетата вече не си пазят стойностите.

Отговор
в отговор на zaphod #8

Re: така няма да стане

So what? Вероятността да се запише точно специалната стойност е 2^32, или 2^64, по твой избор. Така че си имаш дооооста голяма сигурност че ако стойността си е там, то обектът е валиден.

Отговор
в отговор на Pesho® #9

хм...

значи лошото на "случайните" стойности е че много ги влече към проблемните стойности. но дори да са напълно случайни, пак 1/4Е9 не е много - все пак говорим за компютри. ще се случи срванително бързо.

Отговор
в отговор на zzz #10

Re: валиден указател

Екстра!
Със замах пратихме COM-а в небитието....!!!!

Отговор
в отговор на zaphod #11

Re: хм...

Е чак толкова бързо няма да се случи... 2^64 не е толкова малко - иначе brute force разбиванията на сложни криптографски кодове щяха да са ежедневие.

Но по принцип си прав. И това е една от причините, поради които този метод е bad practice. Използвай smart поинтери.

Отговор
в отговор на zaphod #12

Re: валиден указател

Windows API - IsBadCodePtr, IsBadReadPtr, IsBadWritePtr.
Макар да не дават гаранции.

Отговор
в отговор на Zelen #13

Re: валиден указател

Тъкмо щях да ги дам за пример.
Това, което те вътрешно правят е много просто:
try
{
*p=val;
return FALSE;
}
catch(...)
{
return TRUE;
}

Т.е. идеята е, че системата винаги "дава шанс" на програмата да се "поправи" и не я ликвидира без предупреждение.

Отговор
в отговор на Pesho® #14

Тъй-тъй :-)

Браво Пешо,
така се прави во истина

затова и идеята за зануляване на изтрит указател не е лоша.

Макар че, ако адаша смята да ползва например код който вече е написан - може да е по добре да модифицира самиа operator delete (void *);
което ще накара и готовия код да се подчини на правилата му.

Не знам обаче, тъй като тои говори че иска за посигури множестжо указатели на които е присвоена една стойност - да не изтриват повторно паметта - в зависимост от това дали той създава това или се възползва от него - може да е най-добре да определи най-ясно операциите в това множество, като си подходи по царския път и с (няколко) клас(а) опише еднозначно поведението на въпросните пойтери.
Ако не - Смарт Поитер-а на Бууст би се справил прекрасно с това, но този на СТЛ - няма - не е предвиден да прави така, защото има Ownership и няма референс каунтинг - STL's smart poiner e za safe pointer usage vuv oblastta na vidimost naprimer.

Отговор
в отговор на zaphod #15

Re: мен ми трябва за друго

Ima sistemi deto tova go pravyat avtomatichno. (Tochno tova koeto na teb ti tryabva, i koeto predlagat po-dolu). Vij nyakoi Garbage collector za C ili C++.

Nikoga ne sam polzval takova neshto v C/C++ programa, shtoto smyatam che v C/C++ kod e nai dobre chovek da si ima ideya kakvo stava s pametta, ama shtom te marzi....

Отговор
в отговор на Resurrector #16

Re: валиден указател

Da, ama tova she sraboti ako adresa e izvyn adresnoto prostranstvo na processa.
t.e. imash neshto ot tipa:
mov eax, 0xa
call [dword ptr] eax

no ako imash : mov eax, 0x400222
call [dword ptr] eax
tova neshto sys sigurnost she te prati v nebitieto ;-)

Отговор
в отговор на Tikvarova #17

Re: валиден указател

che na koi mu e pritriabval???

Отговор
в отговор на zaphod #18

Re: валиден указател

И така: решение на проблема нема.
с __try и __except, try и catch (SEH или C++ exceptions) проблема ще се реши само ако стойността на адреса е извън адресното пространство на процеса ти. То затова се и слага 0 след като освободиш паметта де. За да те удари през каската защитата на операционната система. За адреси в рамките на процеса - отговорността си носиш самият ти. Можеш да ползваш garbage collector, custom memory allocator, templates от типа safe_delete(T& * p) но едно е важно - не можеш да избягаш от проблема с невалидната памет. Другото е да смениш езика - ползвай с# например. То там проблеми с паметта няма

Отговор
в отговор на lUnknown * #19

Re: валиден указател

В отговор на:

То там проблеми с паметта няма



мда.... и памет също няма...:)

There are 10 types of people in this world one who understand binary jokes and one who not
Отговор
в отговор на zaphod #20

Re: валиден указател

Tova koeto nie polzvame e dynamic_cast za proverka tipa na obekta. Ne e koi znae kolko no e po-dobre ot nisto :)
A inache s custom allocator stava, tova koeto polzvah e header s obraten pointer kam tablica s blokovete vseki blok e s fiksiran razmer. Naprimer a[0] blokove s dalzina 4 byte-a [1]-8 i t.n. Ako dalzinata na tekustia obekt ne savpada s dalzinata na elementa v tablicata ili ako ne sochi kam element v tablicata nesto e schupeno. Pak ne e 100% garantirano, no raboti dosta kulturno i overhead-a e malak. Osven tova reshava problema s fragmentiraneto (vsastnost za tava go i pisah, ne da tarsia corrupted pointer-i). Zadelianeto stava po 4K naprimer, a vatreshno se deli na dazinata na edin element + 16 byte-a za back pointer + size (ako se opitash da napravish size-a po-malak na niakoi sistemi ste pochne da garmi zaradi podravniavane).

Отговор