Да, это вызов функции для еще не построенного объекта, что является неопределенным поведением. Вы не можете обнаружить это надежно. Я бы сказал, что вы также не должны пытаться обнаружить это. Это ничего не произойдет, скорее всего, случайно, по сравнению, например, с вызовом функции для уже удаленного объекта. Попытка поймать все возможные ошибки практически невозможна. Объявленное имя уже видно в его инициализаторе для других полезных целей. Учтите это:
Type *t = (Type*)malloc(sizeof(*t));
Какая распространенная идиома в программировании на C и которая до сих пор работает на C ++.
Лично мне нравится эта история Херба Саттера о нулевых ссылках (которые также недействительны). Суть в том, что не пытайтесь защитить от случаев, которые язык явно запрещает и, в частности, в их общем случае невозможно надежно диагностировать. Со временем вы получите ложную защиту, которая становится довольно опасной. Вместо этого тренируйте свое понимание языка и проектируйте интерфейсы таким образом (избегайте необработанных указателей, ...), который уменьшает вероятность ошибок.
В C ++, а также в C, многие случаи явно не запрещены, а скорее остаются неопределенными. Частично потому, что некоторые вещи довольно сложно диагностировать эффективно , а частично потому, что неопределенное поведение позволяет реализации разрабатывать альтернативное поведение для него вместо того, чтобы полностью его игнорировать - что часто используется существующими компиляторами.
В приведенном выше примере, например, любая реализация может генерировать исключение. Существуют и другие ситуации, которые также являются неопределенным поведением, которое гораздо сложнее эффективно диагностировать для реализации: такой пример - доступ к объекту в другом модуле перевода до того, как он был создан, - который известен как фиаско статического порядка инициализации .