Ответ 1
Относительно того, как это работает (как упоминал MSalters), это касается неправильного наименования.
На самом деле он должен быть назван void*
, конечно.
Но почему он работает для int*
, const char*
и т.д. (фактически любого типа указателя, включая указатель на определенные пользователем типы)?
Ну, я могу предположить, что это связано с очень интересной проблемой обработки исключений в С++ - catch(void*)
обработчик исключений фактически улавливает исключения типа указателя (cv-compatible)!
Пример:
try
{
throw "Catch me if you can!";
}
catch(void* e)
{
// ...and I can!
std::cout << "Gotcha!" << std::endl;
}
Здесь мы бросаем char*
(в литературе Visual С++ char char*
, а не const char*
) и улавливаем его void*
. И это сработает!
Ответ можно найти в С++ Holy Standard:
§15.3 Обработка исключения
15.3.3 Обработчик является совпадением для объекта исключения типа E, если
...
обработчик имеет тип cv1 T * cv2, а E - тип указателя, который может быть преобразован в тип обработчика одним или обоими из - стандартное преобразование указателя (4.10), не включающее преобразование указателей в частные или защищенные или неоднозначные классы
...
И 4.10 говорит, что стандартное преобразование указателя включает преобразование в void*
:
4.10.2 Значение типа "указатель на cv T", где T - тип объекта, может быть преобразовано в указатель типа "указатель" to cv void ".
Отметим также, что отладчик Visual Studio работает аналогичным образом, но не совсем так. Разница в том, что он игнорирует cv-квалификаторы. Таким образом, void
в диалоговом окне "Исключения" означает любой [any cv] void*
. Обработчики уловов будут не игнорировать их:
try
{
struct Throwee {};
const Throwee* t = nullptr;
throw t;
}
catch(void* e)
{
// Will be missed
std::cout << "Gotcha!" << std::endl;
}
catch(const void* e)
{
// Will be catched
std::cout << "Gotcha const!" << std::endl;
}