Принимая во внимание следующий код (и тот факт, что 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 ++ предпочтение в этом случае, предлагая путь вместо другого?
За конвертируемые указатели на фундаментальные типы оба приведения имеют одинаковое значение; так что вы правы, что static_cast
хорошо.
При преобразовании между некоторыми типами указателей, Вполне возможно, что конкретный адрес памяти в указателе необходимо изменить.
Вот где два броска отличаются. static_cast
сделаю соответствующую настройку. reinterpret_cast
не буду.
По этой причине, это хорошее общее правило static_cast
между типами указателей, если вы знать тот reinterpret_cast
желательно
Вам следует static_cast
, использование static_cast
в случаях, когда вы отменяете неявное преобразование.
В этом конкретном случае, однако, нет никакой разницы, потому что вы конвертируете из void*
, А вообще, reinterpret_cast
Положение между двумя указателями объекта определяется как (§5.2.10 / 7):
Указатель на объект может быть явно преобразован в указатель на объект другого типа. Когда prvalue
v
типа «указатель наT1
»Преобразуется в тип« указатель на cvT2
», результат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
когда ты должен.
С помощью 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) и обратно к
Исходный тип возвращает исходное значение указателя. Результат любого
другое такое преобразование указателя не определено.
Больше информации Вот.
Благодаря Джесси Гуд по ссылке.