Casting — Совместимы ли reinterpret_cast и c-style cast (по стандарту C ++)?

Стандарты C ++ упоминают, что reinterpret_cast определяется реализацией и не дает никаких гарантий, кроме того, что приведение обратно (с использованием reinterpret_cast) к исходному типу приведет к тому, что исходное значение будет передано первым.

Приведение в стиле C по крайней мере некоторых типов ведет себя примерно одинаково — приведение результатов вперед и назад с одинаковым значением — В настоящее время я работаю с перечислениями и intс, но есть и другие примеры.

В то время как стандарт C ++ дает эти определения для обоих стилей приведения, дает ли он одинаковую гарантию для смешанных приведений? Если библиотека X возвращается из функции int Y() немного enum значение, может использовать любое из приведенных выше приведений, не беспокоясь о том, какое приведение использовалось для преобразования исходного enum в int в теле Y? У меня нет исходного кода X, поэтому я не могу проверить (и в любом случае он может измениться в следующей версии), и подобные вещи почти не упоминаются в документации.

Я знаю, что при большинстве реализаций в таких случаях оба приведения ведут себя одинаково; Мой вопрос: что стандарт C ++ говорит о таких случаях — если вообще что-нибудь.

0

Решение

C ++ определяет семантику синтаксиса C cast в терминах static_cast, const_cast а также reinterpret_cast, Таким образом, вы получаете одинаковую гарантию для той же операции, независимо от того, какой синтаксис вы используете для ее достижения.

4

Другие решения

reinterpret_cast может использоваться только для конкретных преобразований:

  • Указатель на (достаточно большое) целое число, и наоборот
  • Указатель функции на указатель функции
  • Указатель объекта на указатель объекта
  • Указатель на член указатель на член
  • именующий выражение для ссылки

плюс (условно) указатель функции на указатель объекта и наоборот. В большинстве случаев преобразованное значение не указано, но есть гарантия, что преобразование, за которым следует его обратное, даст исходное значение.

В частности, вы не можете использовать reinterpret_cast конвертировать между целочисленными и перечисляемыми типами; преобразование должно быть сделано с использованием static_cast (или неявно, при преобразовании перечисления с незаданной областью в целочисленный тип), который хорошо определен для достаточно больших целочисленных типов. Единственная возможная проблема в том, что библиотека сделала что-то совершенно безумное, такое как return reinterpret_cast<int&>(some_enum);

Приведение в стиле C выполнит либо static_cast или reinterpret_castс последующим const_cast, как необходимо; поэтому любое преобразование, которое четко определяется static_cast также хорошо определяется броском в стиле C.

2

Нет, reinterpret_cast является не эквивалентно броску стиля C. Броски в стиле C позволяют отбрасывать постоянные переменные (поэтому они включают const_cast) не допускается в reinterpret_cast, Если static_cast допускается между типами источника и назначения, он будет выполнять static_cast который имеет другую семантику, чем reinterpret_cast, Если преобразование не разрешено, оно будет reinterpret_cast, Наконец, есть угловой случай, когда приведение C не может быть представлено в терминах любого другого преобразования: оно игнорирует спецификаторы доступа.

Некоторые примеры, которые иллюстрируют различия:

class b0 { int a; };
class b1 { int b; };
class b2 { int c; };
class d : public b0, public b1, b2 {};
int main() {
d x;
assert( static_cast<b1*>(&x) == (b1*)&x );
assert( reinterpret_cast<b1*>(&x) != (b1*)&x ); // Different value
assert( reinterpret_cast<b2*>(&x) != (b2*)&x ); // Different value,
// cannot be done with static_cast
const d *p = &x;
// reinterpret_cast<b0*>(p);                    // Error cannot cast const away
(b0*)p;                                         // C style can
}
1
По вопросам рекламы [email protected]