2010-08-12 4 views
6

мне нужно написать код для функции обратного вызова (она будет вызываться из АТЛ, но это не очень важно):Может static_cast превратить ненулевой указатель в нулевой указатель?

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 превратил ненулевой указатель в нулевой указатель?

+3

Почему бы просто не бросить безоговорочно и проверить нуль после трансляции? static_cast не собирается разыменовывать указатель. –

+0

@Logan Capaldo: Лучше проверить как можно раньше. – sharptooth

ответ

7

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 было получено путем обхода системы типа. И это означает, что компилятор может сбросить вашу вторую проверку, потому что «это все равно не может произойти».

0

Единственное изменение static_cast должно сделать указатель для выравнивания слов. Итак, теоретически myObjectVoid указал на последний байт в памяти, возможно, что он может быть «выровнен» до 0, но я не вижу в этом реальной проблемы.

+0

Если бы это было возможно, разве это не была бы огромная проблема? Я всегда считал, что 0 - единственное значение, которое не может иметь действительный указатель. – ereOn

+0

Реальный вопрос заключается в том, будет ли адрес округлен вверх или вниз или это реализация определена? –

5

№ Если указатель ссылается на действительный объект, и преобразование является допустимым, тогда результат будет также ссылаться на действительный объект, поэтому он не будет пустым. Если это неверно, то код неверен, и результат не определен. . способ для действительного использования, чтобы дать нулевой результат, чтобы начать с нулевой

в конкретном случае преобразования между объектными указателями и пустыми указателями, стандарт это сказать (5.2.9/10):

Значение типа «указатель на объект», преобразованное в «указатель на void» и обратно к исходному типу указателя, будет иметь свое первоначальное значение.

и это (4,10/3)

В результате преобразования «указатель на T» в «указатель на void» указывает на начало места хранения, где объект типа Т проживает

поэтому первоначальный и конечный указатели на объекты будут одинаковыми, а указатель void будет равен нулю тогда и только тогда, когда указатели на объекты.

0

Нет, вторая проверка не является разумной. Невозможно, чтобы static_cast превратил ненулевой указатель в нулевой указатель.Единственное, что static_cast может измениться по прилагаемому значению в вашем случае (будучи указателем), это настроить адрес. В противном случае это строго связано с консультированием остального анализа типа компилятора, что результат выражения следует рассматривать как целевой тип. Для указателя это означает, что разыменование находит правильный адрес в целевом объекте, и эта последовательность увеличения и уменьшения соответствует размеру типа.

+1

Ну, вот и все. В сценариях, не связанных с реальным миром, передача тщательно обработанного указателя на static_cast может привести к его корректировке смещением, которое делает его NULL. Конечно, этого никогда не произойдет в реальной жизни. –