Può static_cast trasformare un puntatore non nullo in un puntatore nullo?
-
28-09-2019 - |
Domanda
Devo scrivere il codice per una funzione di callback (verrà chiamata da ATL, ma non è molto importante):
HRESULT callback( void* myObjectVoid )
{
if( myObjectVoid == 0 ) {
return E_POINTER;
}
CMyClass* myObject = static_cast<CMyClass*>( myObjectVoid );
return myObject->CallMethod();
}
ecco il void*
è garantito che sia un puntatore a CMyClass
, COSÌ static_cast
è legale.La mia preoccupazione è che il codice debba essere il più portabile possibile (almeno nelle versioni più recenti di Visual C++).Quindi, per essere super paranoico, sono propenso a controllare il file CMyClass*
puntatore - intendo, cosa succede se risulta essere nullo?
if( myObjectVoid == 0 ) {
return E_POINTER;
}
CMyClass* myObject = static_cast<CMyClass*>( myObjectVoid );
if( myObject == 0 ) {
return E_POINTER;
}
Il secondo controllo è ragionevole?È possibile per static_cast
trasformare un puntatore non nullo in un puntatore nullo?
Soluzione
static_cast può cambiare il valore del puntatore, se si esegue il cast tra le parti degli oggetti su diversi offset:
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
Tuttavia, "Il valore puntatore nullo (4.10) viene convertito nel valore del puntatore nullo del
. Tipo di destinazione"(5.2.9-8), cioè se c
è NULL
, allora b
è anche NULL
(e non rettificati) e quindi c2
è impostato NULL
L'intero mezzi cosa:. Se statico lanciando un non-NULL rendimenti myObjectVoid
NULL
, allora il valore di myObjectVoid
è stato ottenuto eludere il sistema dei tipi in qualche modo. E significa, che il compilatore potrebbe buttare il secondo controllo via perché "non può accadere in ogni caso".
Altri suggerimenti
No. Se il puntatore si riferisce ad un oggetto valido, e la conversione è valido, allora il risultato sarà anche riferimento a un oggetto valido, quindi non sarà nullo. Se uno dei due non è valido, allora il codice non è corretto e il risultato è indefinito. Quindi l'unico modo per l'utilizzo valide per dare un risultato nullo è quello di iniziare con null.
Nel caso specifico di conversione tra puntatori all'oggetto e puntatori nulli, lo standard ha questo da dire (5.2.9 / 10):
Un valore di tipo "puntatore a oggetto" convertito "puntatore a
void
" e ritorna al tipo di puntatore originale avrà il suo valore originale.
e questo (4.10 / 3)
Il risultato di conversione di un "puntatore a T" ad un "puntatore a
void
" punta all'inizio della posizione di memoria in cui l'oggetto di tipo T risiede
così i puntatori di oggetto originale e finale sarà lo stesso, e il puntatore void
sarà nullo se e solo se i puntatori sono oggetto.
L'unico cambiamento static_cast
dovrebbe fare per un puntatore è per parola-allineamento. Quindi, in teoria, di myObjectVoid
indicò l'ultimo byte in memoria, è possibile che potrebbe essere 'allineato-up" a 0, ma non vedo che come una preoccupazione realistica.
No, il secondo controllo non è ragionevole.Non è possibile per static_cast
per trasformare un puntatore non nullo in un puntatore nullo.L'unica cosa static_cast
potrebbe cambiare il valore fornito nel tuo caso (essendo un puntatore) è regolare l'indirizzo.Altrimenti si preoccupa strettamente di avvisare il resto dell'analisi del tipo del compilatore che il risultato dell'espressione dovrebbe essere trattato come il tipo di destinazione.Per un puntatore, ciò significa che il dereferenziamento trova l'indirizzo corretto all'interno dell'oggetto di destinazione e che i passi di incremento e decremento sono appropriati alla dimensione del tipo.