2011-08-25 11 views
5

Il seguente pezzo di codice compila senza preavviso per Windows, Mac e iOS:Perché il confronto di un puntatore della funzione membro su NULL genera un avviso?

class MyClass { 
    SomeOtherClass * m_object; 
    void (SomeOtherClass::*m_callback)(); 
public: 
    MyClass(SomeOtherClass * _object,void (SomeOtherClass::*_callback)()=NULL) : 
     m_object(_object),m_callback(_callback) {} 

    void DoStuff() { 
     //generates warning: NULL used in arithmetic when compiling with the Android NDK 
     if (NULL==m_callback) { 
      m_object->DoNormalCallback(); 
     } else { 
      (m_object->*m_callback)(); 
     } 
    } 
}; 

Perché viene generato questo avvertimento e che cosa posso fare?

+0

E 'bello stile per confrontare le cose con 'null', non confrontare' null' con le cose Cambia l'ordine: 'if (m_callback == NULL)' –

+6

È risaputo che il trucco è scrivere if (0 == x) 'in modo che se confondi' == 'con' = ', interromperai la compilazione, non ricevi un avvertimento (o niente). – hamstergene

+0

Alcune linee guida stanno dicendo di mettere la costante sul lato sinistro del confronto per evitare assegnazioni errate. Penso che non ne valga la pena, ma ci sono altre opinioni. – Simon

risposta

2

non credo che si è permesso di confrontare 0 (o NULL) con puntatori a funzione membro, soprattutto perché essi potrebbero non essere in realtà puntatori (quando la funzione è virtual, per esempio).

Personalmente, mi piacerebbe riscrivere il test if senza il confronto, ad es .:

void DoStuff() { 
    if (m_callback) { 
     (m_object->*m_callback)(); 
    } else { 
     m_object->DoNormalCallback(); 
    } 
} 

E, per i punti bonus, eseguire questo test int il costruttore.

class MyClass { 
    SomeOtherClass * m_object; 
    void (SomeOtherClass::*m_callback)(); 
public: 
    MyClass(SomeOtherClass * _object,void (SomeOtherClass::*_callback)()=NULL) : 
     m_object(_object),m_callback(_callback) 
    { 
     // Use "DoNormalCallback" unless some other method is requested. 
     if (!m_callback) { 
      m_callback = &SomeOtherClass::DoNormalCallback; 
     } 
    } 

    void DoStuff() { 
     (m_object->*m_callback)(); 
    } 
}; 
+0

Perché eseguire il test? Basta usare '& SomeOtherClass :: DoNormalCallback' come valore predefinito invece di' NULL'. – Nemo

+0

È possibile convertire una costante del puntatore nullo in un tipo puntatore-membro, vedere # 4.11 dello standard corrente (non sono sicuro di C++ 03 ma dovrebbe essere lo stesso lì). –

4

Se NULL è definito come ((void*)0), è possibile che venga visualizzato un avviso. I puntatori agli oggetti non sono compatibili con i puntatori di funzione. Utilizzare un numero normale 0 anziché NULL. 0 è una costante di puntatore nullo compatibile con entrambi i puntatori di funzione e i tipi di puntatore di oggetto.

EDIT Scusa, non stavo prestando la dovuta attenzione. C'è un puntatore alla funzione membro qui, non solo un puntatore di funzione. Confrontarne uno con ((void*)0) è anche contro le regole e molti compilatori genereranno errori , non solo avvertimenti, su questo.

EDIT 2 A tutti coloro che hanno commentato: so che un compilatore C++ conforme non definirà NULL come ((void*)0). Il problema è che ci sono compilatori non conformi e librerie di terze parti rotte là fuori (ho visto entrambi).

+0

Secondo [una pagina sul sito Web di gcc] (http://gcc.gnu.org/onlinedocs/libstdc++/manual/bk01pt02ch04s03.html) si dice che 'NULL' è definito come' __null', una parola chiave di gcc. –

+0

In C++, 'NULL' non sarà mai definito come' ((void *) 0) '. –

+0

In C++ 'NULL' non può essere definito come' ((void *) 0) '. Se lo fosse, il codice sopra non verrebbe compilato. – ymett

0

if (m_callback) come suggerito da André Caron opere, ma non sono mai stato un fan del cast impliciti a Caccio e preferiscono utilizzare un operatore che restituisce bool. È un po 'prolisso, ma funziona:

if (static_cast<void (SomeOtherClass::*)()>(NULL)==m_callback) 
    m_object->DoNormalCallback(); 
} else { 
    (m_object->*m_callback)(); 
} 

Ancora non sono sicuro del motivo per cui la versione NDCC di GCC richiede il cast.

1

Provare a disattivare l'avviso con -Wno-conversion-null.

0

Prima di C++ 11, il risultato del confronto tra puntatore-membro e '0' non è definito.

In C++ 11, è legittimo confrontare puntatore-a-membro contro il nuovo C++ 11 parola chiave 'nullptr'

Problemi correlati