2011-05-19 24 views
6

Aquí está el ejemplo de la expresión de "cerradura de ámbito" con error común: no se crea una variable local, por lo que el bloqueo no está en vigor. Este código se compila sin problemas tanto con VC++ 2010 y Comeau C++ en línea:Corrección de const con instancias temporales

Si constructor por defecto para ScopedLock está comentado, entonces ambos compiladores dará un error:

error C2512: 'ScopedLock' : no appropriate default constructor available

(Cuando ScopedLock se utiliza correctamente, es decir, se crea una variable local: ScopedLock guard(m_mutex);, a continuación, compilación falla como se esperaba Declarar m_mutex correcciones como mutables el problema)

tengo dos preguntas:..

  1. ¿Por qué X::foo compila? Parece que el compilador pudo convertir const Mutex& en Mutex& de alguna manera.

  2. ¿Qué rol juega ScopedLock constructor por defecto, por lo que la compilación tiene éxito?

Thanks.

Actualización: Encontré la respuesta. Parece que la instrucción ScopedLock(m_mutex); crea una variable local m_mutex del tipo ScopedLock. No es temporal Es por eso que se requiere el constructor predeterminado ScopedLock::ScopedLock.

Respuesta

4

Respondió la pregunta usted mismo.

It appears that ScopedLock(m_mutex); statement creates a local variable m_mutex of type ScopedLock

La explicación se encuentra en la Sección 6 de la Norma.8 La ambigüedad Resolución:

There is an ambiguity in the grammar involving expression-statements and declarations: An expression-statement with a function-style explicit type conversion [5.2.3] as its leftmost subexpression can be indistinguishable from a declaration where the first declarator starts with a (. In those cases the statement is a declaration.

El estándar se enumeran a continuación T(a); como un ejemplo de una declaración de que es realmente una declaración. Es equivalente a T a;

Esta es una variación del infame "análisis más irritante" de C++.

+0

gracias por la respuesta y la cita relevante de la Norma. –

1

Estoy bastante seguro de que su problema es la línea 26: ScopedLock(m_mutex);

En cambio, eso debería ser algo así como ScopedLock a_variable_name(m_mutex);

Cuando hago que el cambio, consigo los errores esperados:

constCorrectness.cpp: In member function ‘void X::foo() const’: 
constCorrectness.cpp:26: error: no matching function for call to ‘ScopedLock::ScopedLock(const Mutex&)’ 
constCorrectness.cpp:18: note: candidates are: ScopedLock::ScopedLock(const ScopedLock&) 
constCorrectness.cpp:11: note:     ScopedLock::ScopedLock(Mutex&) 
constCorrectness.cpp:10: note:     ScopedLock::ScopedLock() 

Quizás alguien pueda interpretar ScopedLock(m_mutex) para nosotros? ¿Declara una función o algo así? En lugar de llamar a un constructor como esperaba el interrogador? Actualización: Apagar esto. Creo que es solo una declaración de variables (es decir, los corchetes se ignoran).

+1

Comentando la pregunta que dejé al final de mi propia respuesta: Creo que su línea 26 simplemente declara otra variable, local para X :: foo, también llamada 'm_mutex'. Los corchetes son básicamente ignorados. Es por eso que usa el constructor predeterminado. –

+0

@ aaron-mcdaid, sí, tienes razón. Lo descubrí solo. Se creó la variable local de tipo 'ScopedLock'. –

+0

Eso está bien. Nunca antes había oído hablar de este idioma, así que gracias por una pregunta interesante. –

0

El problema es que el método X :: foo() se declara como const, lo que significa que no mutará (cambiará) el objeto.

El constructor ScopedLock() no tiene una sobrecarga que acepte una referencia inmutable (const) a un objeto Mutex.

Para solucionar esto, debe declarar m_mutex como mutable, o proporcionar un sobrecargado apropiado del constructor ScopedLock(). Estoy pensando que el primero es preferible.