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

6
задан sharptooth 12 August 2010 в 14:49
поделиться

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

7
ответ дан 8 December 2019 в 18:29
поделиться

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

0
ответ дан 8 December 2019 в 18:29
поделиться

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

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

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

and this (4.10 / 3)

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

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

6
ответ дан 8 December 2019 в 18:29
поделиться

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

0
ответ дан 8 December 2019 в 18:29
поделиться
Другие вопросы по тегам:

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