Правильный способ приведения типов указателей

Принимая во внимание следующий код (и тот факт, что VirtualAlloc() возвращает void*):

BYTE* pbNext = reinterpret_cast<BYTE*>(
VirtualAlloc(NULL, cbAlloc, MEM_COMMIT, PAGE_READWRITE));

почему reinterpret_cast выбран вместо static_cast?

Раньше я думал, что reinterpret_cast в порядке, например, приведение указателей к целочисленным типам (например, DWORD_PTR), но отлить из void* к BYTE*не static_cast ОК?

Есть ли какие-либо (тонкие?) Различия в данном конкретном случае, или они оба являются действительными указателями?

Имеет ли стандарт C ++ предпочтение в этом случае, предлагая путь вместо другого?

45

Решение

За конвертируемые указатели на фундаментальные типы оба приведения имеют одинаковое значение; так что вы правы, что static_cast хорошо.

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

Вот где два броска отличаются. static_cast сделаю соответствующую настройку. reinterpret_cast не буду.

По этой причине, это хорошее общее правило static_cast между типами указателей, если вы знать тот reinterpret_cast желательно

36

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

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

В этом конкретном случае, однако, нет никакой разницы, потому что вы конвертируете из void*, А вообще, reinterpret_castПоложение между двумя указателями объекта определяется как (§5.2.10 / 7):

Указатель на объект может быть явно преобразован в указатель на объект другого типа. Когда prvalue v типа «указатель на T1»Преобразуется в тип« указатель на cv T2», результат static_cast<cv T2*>(static_cast<cv void*>(v)) если оба T1 а также T2 являются типами стандартной компоновки и требованиями выравнивания T2 не более строгие, чем те, T1или если какой-либо тип void, Преобразование значения типа «указатель на T1Указатель на тип T2» (где T1 а также T2 являются типами объектов и где требования выравнивания T2 не более строгие, чем те, T1) и возврат к исходному типу возвращает исходное значение указателя. Результат любого другого такого преобразования указателя не определен.

Акцент мой. поскольку T1 для тебя уже void*актерский состав void* в reinterpret_cast ничего не делает. Это не совсем так, что Дрю Дорманн говорит:

#include <iostream>

template <typename T>
void print_pointer(const volatile T* ptr)
{
// this is needed by oversight in the standard
std::cout << static_cast<void*>(const_cast<T*>(ptr)) << std::endl;
}

struct base_a {};
struct base_b {};
struct derived : base_a, base_b {};

int main()
{
derived d;

base_b* b = &d; // implicit cast

// undo implicit cast with static_cast
derived* x = static_cast<derived*>(b);

// reinterpret the value with reinterpret_cast
derived* y = reinterpret_cast<derived*>(b);

print_pointer(&d);
print_pointer(x);
print_pointer(y);
}

Выход:

00CBFD5B
00CBFD5B
00CBFD5C

(Обратите внимание, что, потому что y на самом деле не указывает на derived, используя это неопределенное поведение.)

Вот, reinterpret_cast придумывает другое значение, потому что проходит через void*, Вот почему вы должны использовать static_cast когда ты можешь, и reinterpret_cast когда ты должен.

21

С помощью static_cast навести указатель на и из void* гарантированно сохранить адрес.

reinterpret_cast с другой стороны, гарантирует, что если вы приведете указатель от одного типа к другому и вернетесь к исходному типу, адрес будет сохранен.

Хотя с большинством реализаций вы увидите те же результаты при использовании любого из них, static_cast должно быть предпочтительным.

И с C++11 Я помню это, используя reinterpret_cast за void* имеет четко определенное поведение. До этого такое поведение было запрещено.

It is not permitted to use reinterpret_cast to convert between pointers to object type and pointers to void.

Предлагаемое решение (август 2010 г.):

Изменить пункт 7.10.10 [expr.reinterpret.cast] следующим образом:

Указатель объекта может быть явно преобразован в указатель объекта
другой тип. Когда значение v типа «указатель на T1» равно
преобразуется в тип «указатель на cv T2», в результате static_cast (static_cast (v)) если оба T1 и T2 являются стандартным макетом
типы (3.9 [basic.types]) и требования выравнивания T2
более строгие, чем у T1, или если какой-либо из типов является недействительным.

Преобразование значения типа «указатель на T1» в тип «указатель на
T2 ”(где T1 и T2 — типы объектов и где выравнивание
требования T2 не являются более строгими, чем требования T1) и обратно к
Исходный тип возвращает исходное значение указателя. Результат любого
другое такое преобразование указателя не определено.

Больше информации Вот.

Благодаря Джесси Гуд по ссылке.

8
По вопросам рекламы [email protected]