Как уже упоминалось @TypeIA, поведение двойного освобождения равно undefined в спецификации C ++.
И, фактически, это было реализовано как пасхальное яйцо в GCC 1.17. Однако обратите внимание, что это было сделано только для «особых случаев». Компилятор должен быть очень и очень уверен, что перед запуском некоторых игр вызывается неопределенное поведение.
В большинстве случаев компилятор не может быть уверен, что запускает пасхальное яйцо. Например. двойные освобождения обычно не реализуются ни в одном методе, как в упрощенном случае. Они случаются, например, после чтения неисправного файла с диска, или если пользователь нажимает кнопки в неправильном порядке и т. д. Эта информация просто недоступна во время компиляции.
Итак, любой нормальный компилятор, вероятно, скомпилирует что-то, что соответствует тому, что вы написали в своем коде. (Однако оптимизатор может помешать вам и удалить неиспользуемые переменные и т. Д. Это иногда необходимо учитывать при написании демонстрационного кода.)
Если бы это было не так, вам нужно было бы жить со страхом, что любая ошибка в вашей программе отправляет электронное письмо вашему работодателю, бросающему вашу работу, публикует все ваши фотографии в Reddit, а затем форматирует ваш жесткий диск.
Хорошо, это мое мнение о неопределенном поведении. Возможно, не очень популярный, и я могу заслужить некоторые отрицательные отзывы за сказанное выше. Тем не менее, Я много отладил , и из моего 10-летнего опыта работы с WinDbg я бы сказал, что в целом все достаточно предсказуемо и отлаживаемо.
Вернуться к исходной проблеме ...
В заголовке вопроса вы написали
освобождение уже освобождено не дает ошибку компилятора
Если вы читали мое заявление раньше, надеюсь, логично, что это будет не ошибка компилятора, а ошибка времени выполнения.
Полагаю, вы имели в виду ошибку времени выполнения, потому что вы также сказали:
С моей точки зрения, должно произойти сбой, но программа работает безупречно
И вы, конечно же, не ожидали сбоя компилятора.
Я скопировал / вставил ваш код в проект Visual Studio 2017 C ++. Я запускал версию x86 в отладочной сборке и сборку выпуска на Windows 7 с пакетом обновления 1 x64 - и он падал оба раза.
Отладочная сборка (запускается в отладчике):
Выпуск сборки (не запускается в отладчике):
В WinDbg вы можете видеть, что деструктор класса вызывает free()
и free()
, вызывает HeapFree()
и HeapFree()
, обнаруживает двойное освобождение и генерирует исключение 0xc0000374
.
0:000> *** Release Build, debugged when crashed
0:000> k
# ChildEBP RetAddr
00 0036f9d0 775bf8a9 ntdll!RtlReportCriticalFailure+0x57
01 0036f9e0 775bf989 ntdll!RtlpReportHeapFailure+0x21
02 0036fa14 7756d95c ntdll!RtlpLogHeapFailure+0xa1
03 0036fa44 0f64fddb ntdll!RtlFreeHeap+0x64
04 0036fa58 0f64fda8 ucrtbase!_free_base+0x1b
05 0036fa68 0137106d ucrtbase!free+0x18
06 (Inline) -------- DeallocateTwice!MyString::{dtor}+0x6 [c:\users\for example john\documents\visual studio 2017\projects\deallocatetwice\mystring.cpp @ 49]
07 0036faa0 01371277 DeallocateTwice!main+0x6d [c:\users\for example john\documents\visual studio 2017\projects\deallocatetwice\deallocatetwice.cpp @ 11]
08 (Inline) -------- DeallocateTwice!invoke_main+0x1c [f:\dd\vctools\crt\vcstartup\src\startup\exe_common.inl @ 78]
09 0036fae8 74f0343d DeallocateTwice!__scrt_common_main_seh+0xfa [f:\dd\vctools\crt\vcstartup\src\startup\exe_common.inl @ 288]
0a 0036faf4 77529802 kernel32!BaseThreadInitThunk+0xe
0b 0036fb34 775297d5 ntdll!__RtlUserThreadStart+0x70
0c 0036fb4c 00000000 ntdll!_RtlUserThreadStart+0x1b
Так что ИМХО, ваше предположение "оно должно рухнуть" было хорошим предположением - я бы тоже это предположил. И это меня не разочаровало.
Как продолжить ...
В следующий раз будьте точны на своем языке, чтобы люди начали доверять вам. Если вы смешиваете время компиляции и время выполнения, или смешиваете стек и кучу, или переворачиваете физическую ОЗУ и виртуальную память, это не очень хорошая отправная точка.
Чтобы получить помощь в таких случаях, вам нужно задать лучшие вопросы. Не спрашивайте, что говорит стандарт C ++. В большинстве случаев это будет «неопределено».
Вместо этого опубликуйте точное окружение, потенциально даже более точное, чем я. Дайте нам номера версий компилятора и параметры командной строки компилятора. Создайте минимальный, полный, жизнеспособный пример для воспроизведения. Покажите свои навыки отладки и как далеко вы зашли.
Тогда кто-то может прийти и дать вам ответ, почему в вашем случае это не сработало, например:
- вы проигнорировали исключение в отладчике (например,
sxi
в WinDbg).
- вы активировали автоматический сбор аварийных дампов. Программа действительно потерпела крах, но вы этого не заметили.
- вы отключили Windows Error Reporting.
- вы подключили отладчик к неправильному процессу.
- ...