Когда использовать reinterpret_cast?

Вы можете проверить, имеет ли ошибка тип WebException, а затем проверить код ответа:

if (e.Error.GetType().Name == "WebException")
{
   WebException we = (WebException)e.Error;
   HttpWebResponse response = (System.Net.HttpWebResponse)we.Response;
   if (response.StatusCode==HttpStatusCode.NotFound)
      System.Diagnostics.Debug.WriteLine("Not found!");
}

или

try
{
    // send request
}
catch (WebException e)
{
    // check e.Status as above etc..
}
413
задан MD XF 13 March 2017 в 01:22
поделиться

6 ответов

Стандарт C++ гарантирует следующее:

static_cast луг указатель на и от void* сохраняет адрес. Таким образом, в следующем, a, b и c вся точка к тому же адресу:

int* a = new int();
void* b = static_cast<void*>(a);
int* c = static_cast<int*>(b);

reinterpret_cast только гарантии, что при кастинге указателя на другой тип, и затем reinterpret_cast это назад к исходному типу , Вы получаете исходное значение. Таким образом в следующем:

int* a = new int();
void* b = reinterpret_cast<void*>(a);
int* c = reinterpret_cast<int*>(b);

a и c содержат то же значение, но значение [1 111] является неуказанным. (на практике это будет обычно содержать тот же адрес как [1 112] и c, но это не указано в стандарте, и это не может быть верно на машинах с более сложными системами памяти.)

Для кастинга к и от [1 114], static_cast должен быть предпочтен.

405
ответ дан leiyc 13 March 2017 в 11:22
поделиться

Один случай, когда reinterpret_cast необходимо, при взаимодействии через интерфейс с непрозрачными типами данных. Это часто происходит в API поставщика, над которыми программист не имеет никакого контроля. Вот изобретенный пример, где поставщик обеспечивает API для того, чтобы сохранить и получить произвольные глобальные данные:

// vendor.hpp
typedef struct _Opaque * VendorGlobalUserData;
void VendorSetUserData(VendorGlobalUserData p);
VendorGlobalUserData VendorGetUserData();

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

// main.cpp
#include "vendor.hpp"
#include <iostream>
using namespace std;

struct MyUserData {
    MyUserData() : m(42) {}
    int m;
};

int main() {
    MyUserData u;

        // store global data
    VendorGlobalUserData d1;
//  d1 = &u;                                          // compile error
//  d1 = static_cast<VendorGlobalUserData>(&u);       // compile error
    d1 = reinterpret_cast<VendorGlobalUserData>(&u);  // ok
    VendorSetUserData(d1);

        // do other stuff...

        // retrieve global data
    VendorGlobalUserData d2 = VendorGetUserData();
    MyUserData * p = 0;
//  p = d2;                                           // compile error
//  p = static_cast<MyUserData *>(d2);                // compile error
    p = reinterpret_cast<MyUserData *>(d2);           // ok

    if (p) { cout << p->m << endl; }
    return 0;
}

Ниже изобретенная реализация демонстрационного API:

// vendor.cpp
static VendorGlobalUserData g = 0;
void VendorSetUserData(VendorGlobalUserData p) { g = p; }
VendorGlobalUserData VendorGetUserData() { return g; }
143
ответ дан jwfearn 13 March 2017 в 11:22
поделиться

Читайте FAQ! При сдержании данных C++ C может быть опасным.

В C++, указатель на объект может быть преобразован в void * без любых бросков. Но это не верно наоборот. Вам было бы нужно static_cast для возвращения исходного указателя.

-14
ответ дан MD XF 13 March 2017 в 11:22
поделиться
  • 1
    Это по любой причине didn' t, кажется, работают также, но это все еще выручило меня! – Joe 4 November 2010 в 22:56

Значение reinterpret_cast не определяется стандартом C++. Следовательно, в теории a reinterpret_cast мог разрушить Вашу программу. В практике компиляторы пытаются сделать то, что Вы ожидаете, который должен интерпретировать биты того, что Вы являетесь передающими в том, как будто они были типом, к которому Вы бросаете. Если Вы знаете то, что компиляторы, которые Вы собираетесь использовать, делают с reinterpret_cast, можно использовать его, но сказать, что это портативно , легло бы.

Для случая Вы описываете, и в значительной степени любой случай, где Вы могли бы рассмотреть reinterpret_cast, можно использовать static_cast или некоторая другая альтернатива вместо этого. Среди прочего стандарт говорит следующее о том, что можно ожидать static_cast (В§5.2.9):

rvalue типа “pointer к условной цене void” может быть явно преобразован в указатель на тип объекта. Значение указателя типа на объект, преобразованный в “pointer к условной цене void” и назад в исходный тип указателя, будет иметь свое исходное значение.

Так для Вашего варианта использования, кажется довольно ясным, что комитет по стандартизации намеревался для Вас использовать static_cast.

18
ответ дан flodin 13 March 2017 в 11:22
поделиться

Одна причина использовать reinterpret_cast состоит в том, когда базовый класс не имеет vtable, но производный класс делает. В этом случае, static_cast и reinterpret_cast приведет к различным значениям указателя (это было бы нетипичным случаем, упомянутым jalf выше ). Так же, как правовая оговорка я не заявляю, что это - часть стандарта, но реализация нескольких широко распространенных компиляторов.

Как пример, возьмите код ниже:

#include <cstdio>

class A {
public:
    int i;
};

class B : public A {
public:
    virtual void func() {  }
};

int main()
{
    B b;
    const A* a = static_cast<A*>(&b);
    const A* ar = reinterpret_cast<A*>(&b);

    printf("&b = %p\n", &b);
    printf(" a = %p\n", a);
    printf("ar = %p\n", ar);
    printf("difference = %ld\n", (long int)(a - ar));

    return 0;
}

, Который производит что-то как:

& b = 0x7ffe10e68b38
= площадь 0x7ffe10e68b40
= различие 0x7ffe10e68b38
= 2

Во всех компиляторах я попробовал (MSVC 2015& 2017, лязгайте 8.0.0, gcc 9.2, ICC 19.0.1 - видят godbolt для последнего 3 ), результат эти static_cast отличается от результата reinterpret_cast 2 (4 для MSVC). Единственный компилятор для предупреждения о различии был лязгом, с:

17:16: предупреждение: 'reinterpret_cast' от класса 'B *' к его основе при ненулевом смещении '*' ведет себя по-другому по сравнению с 'static_cast' [-Wreinterpret-базовый-класс]
константа* площадь = reinterpret_cast (& b);
^ ~~~~~~~~~~~~~~~~~~~~~~~
17:16:примечание: используйте 'static_cast' для корректировки указателя правильно в то время как константа upcasting
* площадь = reinterpret_cast (& b);
^ ~~~~~~~~~~~~~~~
static_cast

Один последний протест состоит в том, что, если базовый класс не имеет никаких элементов данных (например, int i;) тогда, лязгают, gcc, и ICC возвращает тот же адрес для reinterpret_cast что касается static_cast, тогда как MSVC все еще не делает.

1
ответ дан Avi Ginsburg 17 September 2019 в 07:20
поделиться
  • 1
    Вы правы. В этом случае RelativeLayout имеет высоту =" wrap_content" значение его относится к высоте детей. Если Вы определяете ребенка с высотой =" match_parent" тогда этот ребенок обращается к высоте его родителя. Родитель относится к child' s высота и ребенок относится к parent' s один. Я полагаю, что это - то, что RelativeLayout не может обработать, по крайней мере, на данный момент. Вам нужна другая привязка, и я пришел к решению с другим ребенком, который расположен вниз ниже всего другие. – sergej shafarenka 18 August 2013 в 21:35

Вот вариант программы Avi Ginsburg, которая ясно иллюстрирует свойство reinterpret_cast упомянутый Chris Luengo, flodin, и cmdLP: то, что компилятор рассматривает указанный ячейка памяти, как будто это был объект нового типа:

#include <iostream>
#include <string>
#include <iomanip>
using namespace std;

class A
{
public:
    int i;
};

class B : public A
{
public:
    virtual void f() {}
};

int main()
{
    string s;
    B b;
    b.i = 0;
    A* as = static_cast<A*>(&b);
    A* ar = reinterpret_cast<A*>(&b);
    B* c = reinterpret_cast<B*>(ar);

    cout << "as->i = " << hex << setfill('0')  << as->i << "\n";
    cout << "ar->i = " << ar->i << "\n";
    cout << "b.i   = " << b.i << "\n";
    cout << "c->i  = " << c->i << "\n";
    cout << "\n";
    cout << "&(as->i) = " << &(as->i) << "\n";
    cout << "&(ar->i) = " << &(ar->i) << "\n";
    cout << "&(b.i) = " << &(b.i) << "\n";
    cout << "&(c->i) = " << &(c->i) << "\n";
    cout << "\n";
    cout << "&b = " << &b << "\n";
    cout << "as = " << as << "\n";
    cout << "ar = " << ar << "\n";
    cout << "c  = " << c  << "\n";

    cout << "Press ENTER to exit.\n";
    getline(cin,s);
}

, Который приводит к выводу как это:

as->i = 0
ar->i = 50ee64
b.i   = 0
c->i  = 0

&(as->i) = 00EFF978
&(ar->i) = 00EFF974
&(b.i) = 00EFF978
&(c->i) = 00EFF978

&b = 00EFF974
as = 00EFF978
ar = 00EFF974
c  = 00EFF974
Press ENTER to exit.

Таким образом объект B создается в памяти как данные B-specific сначала, сопровождается встроенным объект. static_cast правильно возвраты адрес встроенного объект и указатель, созданный static_cast правильно, дают значение поля данных. Указатель, сгенерированный reinterpret_cast обработки b ячейка памяти, как будто это была плоскость объект, и поэтому когда указатель пытается получить поле данных, это возвращает некоторые данные B-specific, как будто это было содержание этого поля.

Одно использование reinterpret_cast должно преобразовать указатель на целое число без знака (когда указатели и целые числа без знака являются тем же размером):

int i; unsigned int u = reinterpret_cast<unsigned int>(&i);

0
ответ дан 22 November 2019 в 23:16
поделиться
Другие вопросы по тегам:

Похожие вопросы: