2011-08-25 9 views
5

El siguiente fragmento de código se compila sin advertencia para Windows, Mac y iOS:¿Por qué la comparación de un puntero de función miembro a NULL genera una advertencia?

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)(); 
     } 
    } 
}; 

Por qué se genera esa advertencia y qué se puede hacer al respecto?

+0

Es un buen estilo de comparar cosas con 'null', no se pueden comparar' null' con cosas Cambia el orden: 'if (m_callback == NULL)' –

+6

Es un truco muy conocido escribir 'if (0 == x)' de modo que si confundes '==' con '=', romperás la compilación, no acaba de recibir una advertencia (o nada). – hamstergene

+0

Algunas pautas indican que coloque la constante en el lado izquierdo de la comparación para evitar asignaciones erróneas. Creo que no vale la pena, pero hay otras opiniones. – Simon

Respuesta

2

no creo que se le permite comparar 0 (o NULL) con punteros de función miembro, sobre todo porque es posible que no sean en realidad punteros (cuando la función es virtual, por ejemplo).

Personalmente, me gustaría volver a escribir la prueba if sin la comparación, por ejemplo .:

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

Y, para los puntos de bonificación, realizar esta prueba int el constructor.

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

¿Por qué realizar la prueba en absoluto? Simplemente use '& SomeOtherClass :: DoNormalCallback' como el valor predeterminado en lugar de' NULL'. – Nemo

+0

Puede convertir una constante de puntero nulo en un tipo de puntero a miembro, vea el # 4.11 del estándar actual (no estoy seguro acerca de C++ 03 pero debería ser el mismo allí). –

4

Si NULL se define como ((void*)0), puede recibir una advertencia. Los punteros a objetos no son compatibles con los punteros de función. Use un simple 0 en lugar de NULL. 0 es una constante de puntero nulo compatible con puntero de función y tipos de puntero de objeto.

EDIT Disculpa, no estaba prestando la debida atención. Aquí hay un puntero a la función , no solo un puntero a la función. Comparar uno con ((void*)0) también es contrario a las reglas, y muchos compiladores emitirán errores, no solo advertencias, en esto.

EDIT 2 A todos los que comentaron: Sé que un compilador de C++ conforme no definirá NULL como ((void*)0). El problema es que existen compiladores no conformes y bibliotecas de terceros rotas (he visto ambas).

+0

Según [una página en el sitio web de gcc] (http://gcc.gnu.org/onlinedocs/libstdc++/manual/bk01pt02ch04s03.html) dice 'NULL' se define como' __null', una palabra clave de gcc. –

+0

En C++, 'NULL' nunca se definirá como' ((void *) 0) '. –

+0

En C++ 'NULL' no se puede definir como' ((void *) 0) '. Si fuera así, el código anterior no se compilaría. – ymett

0

if (m_callback) como se sugiere por André Caron obras, pero nunca he sido un fan de conversiones implícitas a Bools y prefieren utilizar un operador que evalúa a bool. Es un poco prolijo, pero esto funciona:

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

Aún no sabe por qué la versión de GCC NDK necesita el reparto.

1

Pruebe a desactivar la advertencia con -Wno-conversion-null.

0

Antes de C++ 11, el resultado de comparar puntero-a-miembro contra '0' no está definido.

En C++ 11, es legítimo comparar puntero a miembro contra el nuevo C++ 11 palabras clave 'nullptr'

Cuestiones relacionadas