То, что вы сделали, не является «хорошо разработанным фрагментом кода», но оно работает, потому что, даже если указатель this нулевой, вы никогда (ни явно, ни неявно) не разыменовываете его.
your *p (или p->) относится к классу Test
, а Test::print
не ссылается на что-либо внутри Test, поэтому ... поскольку нулевой тест всегда является тестом и вас не волнует его содержание, код компилируется и работает.
Но этот код может столкнуться с проблемами, если:
Test::print
сделан виртуальным:в этом случае p->print()
(или (*p).print()
) должны пройти v-таблицу фактического объекта, чтобы определить, какую функцию вызывать.(*p
может быть любым * Test
-произведенным), но поскольку объекта нет, v-таблица не может быть обнаружена, и программа завершится сбоем. Test
сделан для того, чтобы иметь членаи ваша функция print
создана для ее печати: в этом случае, поскольку p
указывает на недопустимый блок памяти, ваша функция - при обращении к переменной-члену - попытается неявно разыменовать нулевой указатель, чтобы вычислить, где членявляется.И приведет к неверному адресу памяти, что приведет к сбою.
На самом деле вы только что вошли в эту серую область под названием " undefined поведенческая информация ": юристы языка (те,кто написал спецификации) ничего не сказал об этом (в частности: никогда не говорилось " ошибка (время выполнения) разыменовать неверный указатель ": они сказали " разыменование недопустимого указателя")приводит к неопределенному поведению , что едва означает «мы не хотим говорить вам, что должно произойти»).
Но так как автору компилятора нужно что-то делать (компилятор не может быть «неопределенным»),так как во время компиляции - при переводе строки кода - они не могут знать, каким будет значение указателя, они решили перевести код любым способом.
И так как выполнение кода не прерываетсялюбая граница процесса, она не падает.А поскольку доступ к «неинициализированному пространству в процессе» недоступен, не видны грязные значения и все выглядит хорошо.
Добро пожаловать в слово неуправляемых языков!