Сбитый с толку на С++ литье
Я много читал о С++ casting, и я начинаю запутываться, потому что я всегда использовал C-стиль.
Я прочитал, что на С++ следует избегать стилей стиля C, и что reinterpret_cast очень опасен и не должен использоваться всякий раз, когда есть альтернатива. Напротив, не используя reinterpret_cast, я видел, что он много раз использовал MSDN в своем примере кода. Это заставляет меня задать свой первый вопрос, когда можно использовать reinterpret_cast?
Например:
LRESULT CALLBACK WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
switch (Msg)
{
case WM_CREATE:
{
LPCREATESTRUCT lpCreateStruct = reinterpret_cast<LPCREATESTRUCT>(lParam);
return 0;
}
}
...
}
Если это не так, то как мне присвоить значение LPARAM указателю, используя только статическое, динамическое и/или const-литье?
Также: Если reinterpret_cast не переносится, как бы я переписал его для переносимости (для хорошей практики)
Ответы
Ответ 1
Использование reinterpret_cast приемлемо, если вы знаете, что указатель первоначально был из типа назначения. Любое другое использование использует преимущество, зависящее от реализации, хотя во многих случаях это необходимо и полезно, например, приведение указателя на структуру в указатель на байты, чтобы он мог быть сериализован.
Это считается опасным, поскольку он не проверяет ни во время компиляции, ни во время выполнения. Если вы допустили ошибку, она может и будет сбой и жуть ужасно, и будет трудно отлаживать. Вы, по сути, говорите компилятору: "Я знаю лучше вас, чем это на самом деле, поэтому просто скомпилируйте код и позвольте мне беспокоиться о последствиях".
Ответ 2
Причина, по которой вы видите это в MSDN, заключается в том, что API Win32 является C API, но люди настаивают на предоставлении примеров в С++.
Reinterpret cast отлично работает, когда вы пишете код, который взаимодействует с другими библиотеками. Его следует избегать в вашем собственном приложении.
Ответ 3
Это пример программирования Windows Platform SDK, C API, с С++. Процедура окна имеет только параметры WPARAM и LPARAM, и если вам нужно передать указатель на структуру через оконное сообщение, оно должно быть выполнено. Это, по-моему, вполне приемлемое использование reinterpret_cast < > . Вы не можете избежать трансляции, потому что SDK, на который вы пишете, который не является вашим кодом, не был предназначен для С++, а тем более для безопасности типов, и требует литья, чтобы предоставить общие типы параметров с привязкой C.
Reinterpret_cast < > здесь является флагом, который позволяет вам знать, что вам нужно быть осторожным, но его не следует избегать любой ценой.
Если, с другой стороны, вы контролировали обе стороны кода, API и потребителя, было бы лучше сделать API, который был бы безопасным по типу и не требовал, чтобы потребитель выполнял приведения, чтобы использовать его правильно.
Ответ 4
Не игнорировать MSDN, но MSDN не лучшее место для правильного кодирования на С++.
Одной из причин использования reinterpret_cast является то, что вы бросаете в/из непрозрачных типов данных. reinterpret_cast не является "опасным", это просто, чтобы легко повредить и привести к проблемам в вашем коде, поэтому его следует избегать.
Причиной того, почему предпочтения стиля С++ являются предпочтительными, являются то, что static_cast является типичным, и все время литья легче искать.
Программисты [неправильно] часто используют броски для "отбрасывания предупреждений компилятора", таких как преобразование из целых чисел без знака в подпись или от 32-битного целого до 8-битного.
Ответ 5
По существу reinterpret_cast
является "безопасным" с C-структурами и базовыми типами (исключая простые ошибки, такие как casting int
, для указателя и обратно, который работает на архитектуре ILP32, но ломается на LP64). Структура AC не имеет что-нибудь в нем, кроме возможных дополнений для выравнивания, которые вы не объявили.
reinterpret_cast
небезопасен с полиморфными типами С++, поскольку компилятор вставляет элементы данных в ваш класс - такие вещи, как указатели на виртуальные таблицы и указатели на виртуальные базовые классы. Другие приводы С++ позаботятся об их корректировке, когда, скажем, отбрасывание с указателя на базовый класс на указатель на производный класс, reinterpret_cast
и приведения в стиле C не делают.