2012-07-16 6 views
10

En Visual Studio 2012RC hay algunas extensiones no estándar. Por ejemplo, este código compila:conversión rvalue a lvalue Visual Studio

#include <string> 

using namespace std; 

void value(string& value) 
{ 
    value = "some"; 
} 

int main() 
{ 
    value(string("nice")); 
} 

y recibe una advertencia de que no es una extensión estándar. Entonces, quiero entender, ¿cómo es real y cómo se transforma el código (referencia rvalue o referencia constante con const_cast)?

+1

AFAIK, Visual Studio 2010 (y quizás 2008) también admite este comportamiento. El compilador de VC++ permite modificar objetos temporales. – flamingo

+0

Tenga en cuenta que este es un estilo pobre en el mejor de los casos y propenso a errores en el peor (["¿No le importa que sea un cambio temporal que está modificando?"] (Http://stackoverflow.com/a/1565811/768469)) – Nemo

+1

@ flamingo: Bueno, nunca ha sido ilegal modificar objetos temporales en C++. Siempre se ha permitido llamar a funciones de miembros temporales que no const * modifying * en C++. Sin embargo, adjuntar referencias no const usando sintaxis "directa" es ilegal. El primero realmente le permite a uno trabajar alrededor de este último, como se muestra en mi respuesta. – AnT

Respuesta

8

Un objeto temporal de tipo de clase sigue siendo un objeto. Vive en algún lugar de la memoria, lo que significa que no hay nada inusual en el compilador que pueda adjuntarle una referencia. En el nivel físico, ya sea una referencia constante o una referencia no constante, no hay diferencia. En otras palabras, en casos como ese, la restricción del lenguaje es puramente conceptual, artificial. El compilador simplemente ignora esa restricción. No hay necesidad de "transformar" nada aquí. La referencia se adjunta directamente al objeto, donde sea que ese objeto resida.

Básicamente, para una clase que proporciona la palabra exterior con acceso al valor de su puntero this (o con acceso lvalue a *this) el comportamiento puede ser inmediata y fácilmente simulado

struct S { 
    S& get_lvalue() { return *this; } 
}; 

void foo(S& s); 
... 

foo(S().get_lvalue()); 

El código anterior es perfectamente legal y funciona en torno a la restricción mencionada. Puedes pensar en el comportamiento de MSVC++ como equivalente a esto.

+0

Gracias. Interesante. Aceptado. – ForEveR

+1

si almacenamos las partes fuera de la función, ¿esto puede conducir a una UB? – Guillaume07

+0

@ Guillaume07: ¿Puedes reformularlo? No entiendo lo que quiere decir con "stock". – AnT

3

Básicamente, VS asignará el espacio en alguna parte y dejar que el punto de referencia a ella, como si que era una referencia-a-const sin la constness (o en C++ 11 una referencia rvalue).

Puede desactivar este comportamiento con el interruptor /Za (desactivar las extensiones de lenguaje) compilador bajo

Propiedades -> C/C++ -> Idioma

Si no recuerdo mal.

+0

Gracias. Buena respuesta. Aceptado, pero es malo habilitar/ZA porque ningún código correcto compilará (bajo C++ 11). – ForEveR

+0

No se acepta, porque la respuesta de AndreyT es más útil – ForEveR

3

En C++ estándar no se puede vincular un valor temporal (rvalue/string("nice")) a una referencia no constante (lvalue), pero el compilador de microsoft lo permite. La advertencia le indica que el código se está compilando debido a una extensión y no se compilará con ningún otro compilador.

Cuestiones relacionadas