Могу я привести пример из реальной жизни, где приведение через void * работает, а reinterpret_cast - нет?

Существует ряд вопросов относительно перекрестного преобразования (приведение от T1* к несвязанному T2*), например this и это. Обычно ответ звучит так: reinterpret_cast определяется реализацией, и преобразование в void*, за которым следует static_cast, четко определено. Однако я не видел реальных примеров того, что может пойти не так при использовании reinterpret_cast.

Каковы реальные примеры, когда приведение через void* работает, а reinterpret_cast - нет?


person sharptooth    schedule 06.07.2011    source источник
comment
У меня создалось впечатление, что от reinterpret_cast до char* на самом деле было четко определено (но не указано, да). И это, кроме того, приведение к void* с последующим приведением к неопределенному типу не определено. void* следует использовать только для стирания и восстановления того же типа. (См. Также комментарий Йоханнеса к ответу Павла, в котором говорится примерно то же самое, только более строго.)   -  person Konrad Rudolph    schedule 06.07.2011
comment
@sharptooth: Каковы реальные примеры, когда приведение через void * работает, а reinterpret_cast - нет? Не думаю, что есть такие примеры. Но зачем вам создавать решение для конкретной реализации (даже если поддерживается каждая интересующая вас реализация), если вы можете создать решение со стандартным поведением (и, таким образом, гарантированно переносимым для каждой соответствующей реализации, когда-либо существовавшей)?   -  person Serge Dundich    schedule 06.07.2011
comment
Ответ обычно такой: reinterpret_cast определяется реализацией, а преобразование в void * с последующим static_cast четко определено. тогда обычный ответ неверен.   -  person curiousguy    schedule 13.12.2011
comment
@curiousguy: Правильный ответ приветствуется.   -  person sharptooth    schedule 13.12.2011
comment
@sharptooth Вот он.   -  person curiousguy    schedule 13.12.2011
comment
@curiousguy: Это не выходит за рамки того, что работает, это не то, о чем я просил.   -  person sharptooth    schedule 13.12.2011
comment
@sharptooth Думаю, я не понимаю, о чем вы просите.   -  person curiousguy    schedule 13.12.2011
comment
@curiousguy: Что ж, внимательное изучение Стандарта показывает, что при использовании reinterpret_cast есть место для нежелательного поведения, и я хотел узнать о реальных примерах, если таковые имеются. Вы просто говорите, что он будет работать, даже не пытаясь перечислить системы, на которых он будет работать. Что, если он не работает со встроенным компилятором C ++, который используется в пылесосе, который я куплю завтра?   -  person sharptooth    schedule 13.12.2011
comment
@sharptooth при использовании reinterpret_cast есть место для нежелательного поведения. Как я уже говорил, этот ответ неверен. Стандарт не может определить ни одну из форм, но нет сомнений в том, что цель состоит в том, чтобы обе были четко определены. Вы просто говорите, что он будет работать, даже не пытаясь перечислить системы, на которых он будет работать. Это работает, и все. Это просто так. Повсюду.   -  person curiousguy    schedule 13.12.2011
comment
Действительно, вы придумываете проблему там, где ее нет.   -  person curiousguy    schedule 13.12.2011


Ответы (2)


реальные примеры, когда приведение через void * работает, а reinterpret_cast - нет

Если я интерпретирую это предложение как приведение через void* работает , чтобы помочь мне избежать неопределенного поведения, а reinterpret_cast - нет, то ниже приводится пример.

reinterpret_cast<TYPE*&> (ссылка на указатель) может нарушить строгое правило псевдонима (это происходит, по крайней мере, для g ++) и приведет к неопределенному поведению. Демо.

Однако static_cast<void*&> приведет к ошибке компилятора и избавит вас от такого неопределенного поведения. Демо.

Я видел такое использование в умном указателе:

template<class TYPE>
struct SmartPointer
{
  void *p;
  TYPE& operator ++ ()
  {
    (reinterpret_cast<TYPE*&>(p))++;  // breaking strict aliasing rule
    return *this;
  }
}
person iammilind    schedule 06.07.2011
comment
@sharptooth, я вложил в ответ реальный код. Посмотрим, поможет ли это. - person iammilind; 06.07.2011
comment
reinterpret_cast<TYPE*&> Кто это предложил? - person curiousguy; 13.12.2011
comment
@curiousguy, какое это имеет значение? Этот фрагмент кода показывает reinterpret_cast<> в плохом свете (что нарушает строгие правила псевдонима). - person iammilind; 13.12.2011
comment
@iammilind Я не понимаю, к чему вы клоните. Этот фрагмент кода показывает использование reinterpret_cast, которое не определено должным образом, и это не то, что OP хотел сделать. - person curiousguy; 13.12.2011
comment
@curiousguy, я не знаю, проголосовали ли вы против, но вопрос в ... where reinterpret_cast<void*> doesn't work .... Пример, который я привел, отвечает тем же. reinterpret_cast<void*&> не генерирует ошибку компилятора и незаметно приводит к неопределенному поведению, что по сути означает, что это не работает. - person iammilind; 15.12.2011
comment
Да, reinterpret_cast<void*&> не работает. Но вопрос не в этом! Спрашивается: когда два static_cast подряд конвертируют из T* в U*, как я хочу, а один reinterpret_cast - нет? И ответ: никогда, вы придумываете проблему, которой не существует, на основании предыдущих неправильных ответов, данных на SO. - person curiousguy; 15.12.2011
comment
reinterpret_cast<void*&> здесь недопустимое использование reinterpret_cast (и редко бывает уместным). reinterpret_cast ‹void * &› не генерирует ошибку компилятора и незаметно приводит к неопределенному поведению. Обычно то, что делает приведение при неправильном использовании, выдает UB. - person curiousguy; 15.12.2011

приведение из T1 * к несвязанному T2 * с reinterpret_cast не менее определено, чем с static_cast. Фактически, когда и T1, и T2 являются стандартными типами макета, он работает одинаково (см. 5.2.10 / 7):

Когда prvalue v типа «указатель на T1» преобразуется в тип «указатель на cv T2», результатом будет static_cast ‹cv T2 *› (static_cast ‹cv void *› (v))

Для нестандартных типов макета результат преобразования не указан, но он также не указан для static_cast.

Я думаю, вы можете получить разницу только при приведении типов, не являющихся указателями, в таких искусственных случаях, как это:


struct Foo
{
};

struct Bar
{
    operator void*()
    {
        return 0;
    }
};

int main ()
{
  Bar b;
  Foo * p1 = static_cast<Foo*>(static_cast<void *>(b)); // ok, Bar::operator void* -> static_cast
  Foo * p2 = reinterpret_cast<Foo*>(b); // error, no conversion from Bar to Foo*.
}

person Konstantin Oznobihin    schedule 06.07.2011
comment
Возможно, Sharptooth говорит о текущем стандарте C ++ 03, а не о проекте, который вы цитируете. Хотя на самом деле я думаю, что он, вероятно, говорит о том, идет ли что-то не так на практике, поэтому оба стандарта не имеют отношения к тому, что на самом деле реализации - C ++ 03 не имеет значения, потому что все известные реализации имеют больше общего между своими reinterpret_cast реализациями, чем фактически гарантировано, и FDIS, потому что никто еще не обещает его реализовать. - person Steve Jessop; 06.07.2011