Подтвердить что ты не робот

Сбитый с толку на С++ литье

Я много читал о С++ 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 не переносится, как бы я переписал его для переносимости (для хорошей практики)

4b9b3361

Ответ 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 не делают.