валиден указател
23 отговора
940 прегледа
валиден указател
как мога да разбера дали даден указател е валиден? имам предвид нещо от рода:
int *a,*b;
a=new int;
b=new int;
delete a;
ASSERT(!IsValidPointer(a));
ASSERT(IsValidPointer(b));
забелязал съм че когато трия вече изтрит указател, хийпа гърми, а ако имаше начин да се провери, предполагам нямаше да гърми, защото щеше да се усети че му пробутвам за изтриване невалиден указател.
int *a,*b;
a=new int;
b=new int;
delete a;
ASSERT(!IsValidPointer(a));
ASSERT(IsValidPointer(b));
забелязал съм че когато трия вече изтрит указател, хийпа гърми, а ако имаше начин да се провери, предполагам нямаше да гърми, защото щеше да се усети че му пробутвам за изтриване невалиден указател.
Re: валиден указател
Доколкото съм запознат много добра практика е да се дефинира някакъв макрос SAFE_DELETE, който освен delete на указателя да го прави и равен на NULL. Идеята е вместо обикновения delete да викаш въпросния макрос и работата е готова. IsValidPointer ще проверява само дали указателят е NULL.
мен ми трябва за друго
трябва ми за случай когато на тоя указател има много направени копия. по принцип такъв проблем трябва да се реши организационно - да се погрижа копията да се знаят, обаче е много сложно. пробвах дали четенето и записа в изтрит указател могат да се хванат със try catch, обаче не става.
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 е разрешена операция и не прави нищо.
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 е разрешена операция и не прави нищо.
Re: мен ми трябва за друго
В твоя случай май по-скоро трябва да се ориентираш към smart pointers или reference counting.
Има и друга алтернатива, но не е много добра, и върши работа само за поинтери към твои си структури и класове, върху които имаш контрол. За int* няма да стане. Идеята е да вкараш във class/struct-а си някое поле със специална стойност, например unsigned magic = 0xABEDEEBA; В конструктора на класа/структурата го сетваш със специалната стойност, а в деструктора го нулираш. Съответно, ако искаш да провериш дали поинтера сочи към валиден обект, просто проверяваш дали е ненулев и дали съответното поле има въпросната специална стойност. Разбира се, тоя метод може да се издъни лесно при неправилна употреба - например ако оставиш поинтера да сочи някъде съвсем на майната си, програмата ти сигурно ще гръмне с page fault. И изобщо си е bad practice, казвам го само за пълнота.
Има и друга алтернатива, но не е много добра, и върши работа само за поинтери към твои си структури и класове, върху които имаш контрол. За int* няма да стане. Идеята е да вкараш във class/struct-а си някое поле със специална стойност, например unsigned magic = 0xABEDEEBA; В конструктора на класа/структурата го сетваш със специалната стойност, а в деструктора го нулираш. Съответно, ако искаш да провериш дали поинтера сочи към валиден обект, просто проверяваш дали е ненулев и дали съответното поле има въпросната специална стойност. Разбира се, тоя метод може да се издъни лесно при неправилна употреба - например ако оставиш поинтера да сочи някъде съвсем на майната си, програмата ти сигурно ще гръмне с page fault. И изобщо си е bad practice, казвам го само за пълнота.
Редактирано от Pesho® на
така няма да стане
защото когато изтриеш обекта хийпа записва някаква информация отгоре му и полетата вече не си пазят стойностите.
Re: така няма да стане
So what? Вероятността да се запише точно специалната стойност е 2^32, или 2^64, по твой избор. Така че си имаш дооооста голяма сигурност че ако стойността си е там, то обектът е валиден.
хм...
значи лошото на "случайните" стойности е че много ги влече към проблемните стойности. но дори да са напълно случайни, пак 1/4Е9 не е много - все пак говорим за компютри. ще се случи срванително бързо.
Re: хм...
Е чак толкова бързо няма да се случи... 2^64 не е толкова малко - иначе brute force разбиванията на сложни криптографски кодове щяха да са ежедневие.
Но по принцип си прав. И това е една от причините, поради които този метод е bad practice. Използвай smart поинтери.
Но по принцип си прав. И това е една от причините, поради които този метод е bad practice. Използвай smart поинтери.
Re: валиден указател
Windows API - IsBadCodePtr, IsBadReadPtr, IsBadWritePtr.
Макар да не дават гаранции.
Макар да не дават гаранции.
Re: валиден указател
Тъкмо щях да ги дам за пример.
Това, което те вътрешно правят е много просто:
try
{
*p=val;
return FALSE;
}
catch(...)
{
return TRUE;
}
Т.е. идеята е, че системата винаги "дава шанс" на програмата да се "поправи" и не я ликвидира без предупреждение.
Това, което те вътрешно правят е много просто:
try
{
*p=val;
return FALSE;
}
catch(...)
{
return TRUE;
}
Т.е. идеята е, че системата винаги "дава шанс" на програмата да се "поправи" и не я ликвидира без предупреждение.
Тъй-тъй :-)
Браво Пешо,
така се прави во истина
затова и идеята за зануляване на изтрит указател не е лоша.
Макар че, ако адаша смята да ползва например код който вече е написан - може да е по добре да модифицира самиа operator delete (void *);
което ще накара и готовия код да се подчини на правилата му.
Не знам обаче, тъй като тои говори че иска за посигури множестжо указатели на които е присвоена една стойност - да не изтриват повторно паметта - в зависимост от това дали той създава това или се възползва от него - може да е най-добре да определи най-ясно операциите в това множество, като си подходи по царския път и с (няколко) клас(а) опише еднозначно поведението на въпросните пойтери.
Ако не - Смарт Поитер-а на Бууст би се справил прекрасно с това, но този на СТЛ - няма - не е предвиден да прави така, защото има Ownership и няма референс каунтинг - STL's smart poiner e za safe pointer usage vuv oblastta na vidimost naprimer.
така се прави во истина
затова и идеята за зануляване на изтрит указател не е лоша.
Макар че, ако адаша смята да ползва например код който вече е написан - може да е по добре да модифицира самиа operator delete (void *);
което ще накара и готовия код да се подчини на правилата му.
Не знам обаче, тъй като тои говори че иска за посигури множестжо указатели на които е присвоена една стойност - да не изтриват повторно паметта - в зависимост от това дали той създава това или се възползва от него - може да е най-добре да определи най-ясно операциите в това множество, като си подходи по царския път и с (няколко) клас(а) опише еднозначно поведението на въпросните пойтери.
Ако не - Смарт Поитер-а на Бууст би се справил прекрасно с това, но този на СТЛ - няма - не е предвиден да прави така, защото има Ownership и няма референс каунтинг - STL's smart poiner e za safe pointer usage vuv oblastta na vidimost naprimer.
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....
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....
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 ;-)
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 ;-)
Re: валиден указател
И така: решение на проблема нема.
с __try и __except, try и catch (SEH или C++ exceptions) проблема ще се реши само ако стойността на адреса е извън адресното пространство на процеса ти. То затова се и слага 0 след като освободиш паметта де. За да те удари през каската защитата на операционната система. За адреси в рамките на процеса - отговорността си носиш самият ти. Можеш да ползваш garbage collector, custom memory allocator, templates от типа safe_delete(T& * p) но едно е важно - не можеш да избягаш от проблема с невалидната памет. Другото е да смениш езика - ползвай с# например. То там проблеми с паметта няма
с __try и __except, try и catch (SEH или C++ exceptions) проблема ще се реши само ако стойността на адреса е извън адресното пространство на процеса ти. То затова се и слага 0 след като освободиш паметта де. За да те удари през каската защитата на операционната система. За адреси в рамките на процеса - отговорността си носиш самият ти. Можеш да ползваш garbage collector, custom memory allocator, templates от типа safe_delete(T& * p) но едно е важно - не можеш да избягаш от проблема с невалидната памет. Другото е да смениш езика - ползвай с# например. То там проблеми с паметта няма
Re: валиден указател
В отговор на:То там проблеми с паметта няма
мда.... и памет също няма...:)
There are 10 types of people in this world one who understand binary jokes and one who not
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).
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).