2011-06-29 13 views
11

Considere el siguiente código:¿Por qué no hay advertencia de gcc/g ++ para los temporales no utilizados?

void ListenerImpl::attach(boost::shared_ptr<ISubscriber> subscriber) 
{ 
    boost::unique_lock<boost::mutex>(mtx); 
    subscribers.push_back(subscriber); 
} 

void ListenerImpl::notify(MsgPtr msg) 
{ 
    boost::unique_lock<boost::mutex>(mtx); 

    //notify all subscribers 
    BOOST_FOREACH(boost::shared_ptr<ISubscriber> subscriber, subscribers){ 
     subscriber->update(msg); 
    } 

} 

(. Esta es una implementación de un patrón de observador como se describe en GoF) La intervención del usuario aquí era proteger el pegado() y el Notify() de ejecución simultánea, de ahí el impulso :: unique_lock. El objetivo era proteger el contenedor subscribers.

Pero de hecho es extremadamente difícil notar que los bloqueos son de hecho solo temporales (échele un vistazo más de cerca, no hay nombres asignados para ellos). Por lo que el bloqueo en el mutex se liberará inmediatamente, cuando se destruya el temporal, es decir, el código no es seguro para subprocesos. Me esperaba en situaciones como esta una advertencia de compilador. Algo así como "temporal no utilizado".

Peor aún, cppcheck tampoco reconocería este error. (cppcheck: una herramienta de análisis de código c/C++ http://sourceforge.net/apps/mediawiki/cppcheck/index.php?title=Main_Page)

Gcc emite advertencias en variables no utilizadas. El temporal aquí es una variable no utilizada, y definitivamente el resultado de la falta de atención del programador. Entonces, ¿por qué no hay advertencias en casos como este? Tal vez es demasiado complicado descubrir tales situaciones?

+1

Cometí un error similar, compruebe también esta pregunta: http://stackoverflow.com/questions/914861/disallowing-creation-of-the-temporary-objects – Naveen

+0

¿Ha intentado -Wall -Wextra como argumentos de línea de comandos para el compilador? Aunque no estoy familiarizado con C++. – DipSwitch

+0

¿Se garantiza que una variable no modificada (lo que se conoce como * temporal *) se destruya inmediatamente? Hubiera esperado que viviera hasta el final del alcance que se definió. – ereOn

Respuesta

8

El compilador no emite una advertencia, porque es muy posible que esté actualizando alguna variable static-member/global dentro del constructor (que es válida y significativa). ej .:

struct A 
{ 
    static int count; 
    A() { count ++; } 
}; 

Ahora, cuando simplemente se le invoca un temporal:

A(); 

En caso de que dicha actualización no está sucediendo, compilador no cavar en el constructor de A y comprobar si algo útil está sucediendo. Siempre supone que es un escenario válido. Hay muchos casos similares que se pueden señalar relacionados con los temporales.

+7

Y de hecho, algo * está * sucediendo en el caso presentado por la pregunta: el mutex está bloqueado y liberado, lo que desencadena una sincronización de caché a través de los hilos ... ¿cómo puede el compilador saber que no era todo lo que se quería? –

+1

El compilador debe emitir advertencias cada vez que el programador hace algo potencialmente peligroso. Por ejemplo, lo hace cuando haces algo como "if (i = 0)", donde probablemente querías escribir "if (i == 0)". Es posible que haya hecho esto de forma intencionada (por ejemplo, "if (result = doSomething())", pero como generalmente no es lo que quiere, hay una advertencia al respecto. ¿No debería ser este el caso también de variables temporales? – petersohn

0

Tenga en cuenta que su advertencia propuesta también se emitirá para cada it++;, que se encuentra en muchos bucles for.

iammilind ya ha mencionado que a veces es por intención crear y destruir inmediatamente la temperatura: cuando hay efectos secundarios.

Y en la meta programación de plantillas, se puede crear y destruir un programa temporal, en caso de que el usuario suministre una clase con efectos secundarios. Cuando se usa una clase simple, sin efectos secundarios, para crear una instancia de la plantilla, las advertencias aparecerán en el fondo en el código de la plantilla. Por favor, su advertencia propuesta tendrá muchos falsos positivos. Será difícil encontrar las advertencias genuinas entre los espurios.

Así que espero que los proveedores de compiladores hayan decidido que su tiempo se gasta mejor en otro lugar.

0

hmm .. No estoy seguro, pero no se puede proteger contra esto con el C++ normal también?

class Mutex; 
class Lock { 
    Lock(Mutex *mutex); 
}; 

int main() { 
    Lock /* lock */ (&mtx); 
    return 0; 
} 

me sale esta advertencia del compilador al compilar con DJGPP:

C:\df>gxx -c a.cpp 
a.cpp: In function 'int main()': 
a.cpp:8:30: error: 'mtx' declared as reference but not initialized 

Se compila bien si Descomentar "LOCK" y añadir una variable mutex.

Por lo tanto, si su variable "mtx" es un puntero. Qué sucede si lo cambia y lo pasa como "& mtx" en su lugar.

Cuestiones relacionadas