| Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
| Форум программистов > C/C++: Общие вопросы > где логика работы с указателями? |
| Автор: yours-tester 6.2.2005, 14:47 | ||
| Начал изучать C++ с помощью VC6++ на winXP Не могу найти ответ на интересующий меня вопрос. Разобрал пример и он привёл меня в ступор. А правильно ли я выбрал язык на котором хочу кое-что написать? Что то какая то нелогичность получается в этом языке с указателями пример приведён ниже, если не перегружать оператор присваивания (закоментировать первый #define), то после команды Str3=Str2=Str1 Str1.s, Str2.s, Str3.s - указывают на одну и ту же строку но это ещё пол беды, когда после Str1.destroy() вызывается Str2.destroy() происходит ошибка приложения и Windows пытается отослать в Microsoft сообщение об ошибке. Оно понятно что, Str2.s уже указывает, на освобождённую память, но неужели оператор delete этого не может распознать и корректно отработать этот случай? Что за этим разве программист должен следить? Вот учебный пример
|
| Автор: S.A.P. 6.2.2005, 15:15 | ||
|
| Автор: srd 6.2.2005, 15:15 | ||
| Ну и? Повторное освобождение уже освобождённой памяти является грубейшей ошибкой в любом языке программирования, поддерживающем работу с указателями, в том числе и в тех, которые имеют сборщик мусора (типа явы или си шарпа). Всё просто и логично. Добавлено @ 15:18
Отладочная версия run-time может обнаруживать повторное освобождение памяти и выдавать исключение. Релизная версия будет молча ломать кучу, из-за чего баг будет вылазить совсем в другом месте. |
| Автор: Domestic Cat 6.2.2005, 20:11 | ||
Не понял, как в менеджед языках можно повторно память освободить? |
| Автор: chipset 6.2.2005, 20:13 |
| Перегрузи функцию delete и заставь её проверять NULL ли обьект перед удалением, и обнулять его в противном случае. Мы так делаем Добавлено @ 20:15 Так, на будущее... пользуйся плз тегами [code=cpp][/code], удобнее читать просто http://forum.sources.ru/smiles/Main/wink.gif |
| Автор: En_t_end 6.2.2005, 20:20 |
| Вообще фигня полная !!! Первый раз вижу такую тупую реализацию! |
| Автор: chipset 6.2.2005, 20:21 |
| En_t_end, насчёт стиля ничего плохого сказать не могу... |
| Автор: Конструктор 6.2.2005, 20:39 |
| chipset, кажысь стандартная реализация и так проверяет не NULL-ли объект, тока сама в NULL не ставит при удалении. Вроде где то я читывал что по стандарту совершенно безопасно применить delete к NULL указателю |
| Автор: yours-tester 6.2.2005, 20:59 |
| Вообще то здесь delete применяется не к NULL указателю, а к перекрёстному указателю, который не равен NULL, но указывает на уже освобождённую память. Вопрос в том, есть ли способ узнать, что не NULL указатель указывает на освобождённую память. И не освобождать её вторично. Отладчик ведь откуда то об этом знает и покрасил мне переменные в красный цвет. А оператор delete почему не может узнать этого? |
| Автор: Конструктор 6.2.2005, 22:02 |
| А зачем ему? Ему скорость важна, а если не важна то как и было замечено Java и C# |
| Автор: gepard 7.2.2005, 11:31 | ||||||
Конструктор
Ошибаешься... yours-tester
Значит - NULL. Указатель - это как человек, который указывает на область памяти пальцем. Он тычит и говорит: "Вот здесь". А раз он NULL, то он - 0...0 - это NULL, NULL - это 0... Если ты пишешь:
Это значит, что Человек с именем str3 тычет пальцем на область памяти, куда тычат str1 и str2. Если ты удалил эту область, то получается, что тыкать-то им некуда. str1.Destroy(); - парень с именем str1 перестаёт тыкать пальцем на область памяти. str2.Destroy(), str3.Destroy(); - str2 и str3 рады перестать тыкать, но они уже перестали и второй раз перестать не могут... |
| Автор: srd 7.2.2005, 11:53 | ||||||||||
Ага, заврался я
А вот повторного освобождения я не добился, как ни пытался.
Да нет, с точки зрения стандарта применять delete к нулевому указателя безопасно.
|
| Автор: S.A.P. 7.2.2005, 12:06 | ||||
На сколько я знаю, не во всех реализациях языка NULL есть 0. Поэтому для указателей лучше все таки использовать NULL. Стандарт языка гарантирует, что по адресу NULL ничего не будет и все операции с ним абсолютно безопасны. А delete 0 может не прокатить. |
| Автор: srd 7.2.2005, 12:58 |
| Если мы говорим про Си++, то в стандарте есть понятие 0 как нулевого указателя, но нет ничего про NULL. Это просто наследине из Си-шной CRT. Более того, компилятор всегда может интерпретировать 0 как нулевой указатель, а вот NULL в разных реализациях может быть определён как 0, как (void *)0, как (long *)0 и т.п. Это может создать проблемы. Так что, что лучше - ещё вопрос. |
| Автор: gepard 7.2.2005, 14:51 |
| srd Твоя правда... Но только в том случае, если указатель точно "0". Добавлено @ 14:54 Если delete вызывать после delete, то будет лаг... |
| Автор: S.A.P. 7.2.2005, 22:19 | ||
А вот то, что 0 применительно к указателям конвертируется в NULL, пожалуй, соглашусь, но все равно лучше все таки юзать NULL для указателей. Так спокойней, да и мало ли какая реализация C++ попадется |
| Автор: srd 8.2.2005, 03:13 | ||
В приведённой тобой ссылке как раз и говорится, что макрос NULL, определённый в заголовках <clocale>, <cstddef>, <cstdio>, <cstdlib>, <cstring>, <ctime> или <cwchar> - это зависящая от реализации константа для нулевого указателя. Обрати внимание, что все эти заголовки из CRT. Если есть под рукой стандарт, посмотри, что там говорится про null-pointer, а не про макрос NULL.
0 не конвертируется в NULL, он интерпретируется компилятором как нулевой указатель, точно так же, как интерпретируется как нулевой указатель конкретное значение макроса NULL. Проблема в том, что 0 - везде 0, а макрос NULL может отличаться в разных реализациях. Так что я с тобой не соглашусь, лучше всё-таки использовать просто 0. |
| Автор: Adil' 8.2.2005, 11:38 | ||||
|
| Автор: srd 8.2.2005, 12:15 | ||||||||
Боюсь вы меня не понимаете. В стандарте явно сказано, что 0, когда он применяется к указателям, всегда интерпретируется как нулевой указатель, не зависимо от того, чем нулевой указатель является в данной реализации и на данной машине в действительности, хоть 0xaabbccdd. А вот если вы напишете
то фиг вы это скомпилируете компилятором, где, например, NULL определён как
Кажется в документации wxWidgets приводился пример такого загадочного определения макроса NULL и вытекающие отсюда проблемы. Ещё раз, NULL достался в наследство от Си, а компилятор Си более равнодушно относится к присваиваниям указателей разных типов, потому там подобная проблема и не стояла. Добавлено @ 12:20 Кстати, Страуструп в своём FAQ говорит, что в Си++ макрос NULL - всегда 0.
Смотрим http://www.research.att.com/~bs/bs_faq2.html#null |
| Автор: Adil' 8.2.2005, 12:22 | ||||
Добавлено @ 12:31
|