Может ли static_cast превратить ненулевой указатель в нулевой указатель?
Мне нужно написать код для функции обратного вызова (она будет вызываться изнутри ATL, но это не очень важно):
HRESULT callback( void* myObjectVoid )
{
if( myObjectVoid == 0 ) {
return E_POINTER;
}
CMyClass* myObject = static_cast<CMyClass*>( myObjectVoid );
return myObject->CallMethod();
}
здесь void*
гарантированно будет указателем на CMyClass
, так static_cast
законно Меня беспокоит то, что код должен быть максимально переносимым (по крайней мере, для более новых версий Visual C++). Так что, чтобы быть супер-параноиком, я склонен проверить CMyClass*
указатель - я имею в виду, что если он окажется нулевым?
if( myObjectVoid == 0 ) {
return E_POINTER;
}
CMyClass* myObject = static_cast<CMyClass*>( myObjectVoid );
if( myObject == 0 ) {
return E_POINTER;
}
Является ли вторая проверка разумной? Это возможно для static_cast
превратить ненулевой указатель в нулевой указатель?
4 ответа
static_cast может изменить значение указателя, если вы приведете между частями объекта на разных смещениях:
class A{ int x; }; class B{ int y; };
class C : A,B {};
C *c=new C();
B *b=c;
// The B part comes after the A part in C. Pointer adjusted
C *c2=static_cast<C*>(b);
// Pointer gets adjusted back, points to the beginning of the C part
Однако "значение нулевого указателя (4.10) преобразуется в значение нулевого указателя типа назначения". (5.2.9-8), т.е. если c
является NULL
, затем b
это также NULL
(и не корректируется) и, таким образом c2
установлен в NULL
, Все это означает: если статическое приведение не NULL myObjectVoid
доходность NULL
тогда значение myObjectVoid
был получен путем обхода системы типов как-то. А это значит, что компилятор может выбросить вашу вторую проверку, потому что "это все равно не может произойти".
Нет. Если указатель ссылается на действительный объект, и преобразование является действительным, то результат также будет ссылаться на действительный объект, поэтому он не будет нулевым. Если любой из них недействителен, то код неверен, а результат не определен. Таким образом, единственный способ для правильного использования дать нулевой результат - начать с нуля.
В конкретном случае преобразования между указателями на объекты и указателями на пустоту в стандарте говорится следующее (5.2.9/10):
Значение типа "указатель на объект", преобразованное в "указатель на
void
"и обратно к исходному типу указателя будет иметь свое первоначальное значение.
и это (4.10/3)
Результат преобразования "указателя на T" в "указатель на
void
"указывает на начало места хранения, где находится объект типа T
поэтому указатели исходного и конечного объекта будут одинаковыми, а void
Указатель будет нулевым, если и только если указатели объекта.
Единственное изменение static_cast
должен сделать указатель для выравнивания слов. Итак, в теории, myObjectVoid
указывает на последний байт в памяти, возможно, он может быть "выровнен" до 0, но я не вижу в этом реальной проблемы.
Нет, вторая проверка не является разумной. Это невозможно для static_cast
превратить ненулевой указатель в нулевой указатель. Единственная вещь static_cast
Может измениться о предоставленном значении в вашем случае (будучи указателем) является настройка адреса. В противном случае это строго связано с сообщением остальной части анализа типов компилятора, что результат выражения должен рассматриваться как целевой тип. Для указателя это означает, что разыменование находит правильный адрес в целевом объекте, и что шаги увеличения и уменьшения соответствуют размеру типа.