sirve que punteros puntero programacion poo para orientada objetos objeto definicion declarar constante como c++ pointers c++11 const auto

c++ - que - Devolver un puntero de const a un miembro de datos const y la palabra clave ''auto''. Un poco confundido



punteros en c++ definicion (4)

Recientemente he estado aprendiendo C ++ y hoy mismo he sido introducido a const y al concepto de corrección de const. En un intento por comprender mejor la teoría, he estado escribiendo una serie de programas simples para asegurarme de que entiendo el concepto correctamente. Pensé que entendía todo, pero cuando uso la palabra clave auto en uno de los programas, parece que me he quedado un poco atascado.

Para probar que entendí cómo funcionan los punteros const, escribí un programa simple. No me molestaré en publicar todo esto, ya que solo hay dos partes relevantes. Tengo una clase con un miembro de datos const de tipo int:

const int tryToChangeMe;

Dentro de esta clase también tengo una función miembro que devuelve un puntero a la constante anterior:

const int* const MyClass::test() { return &tryToChangeMe; }

En mi función principal, luego llamo a la función anterior, haciendo uso de la palabra clave auto . Para probar que lo que creo que sé sobre const es correcto, luego intento reasignar la variable tryToChangeMe a través del puntero. Al igual que:

auto temp = myClass.test(); *temp = 100;

Como esperaba, el programa no se compilaría debido al error que causé al intentar asignar un valor a una variable const . Sin embargo, no solo devolví un puntero a const , sino que devolví un puntero de const a una const (al menos eso es lo que pensé que hice). Entonces, para probar esto, intenté reasignar el puntero a una nueva dirección de memoria, bastante seguro de que obtendría un error de compilación similar:

temp = new int;

Pero bastante confuso el programa compilado sin ningún problema. Pasar por el depurador reveló que, efectivamente, el puntero estaba perdiendo su dirección original y se le asignó una nueva. Preguntándome qué estaba pasando, simplemente tuve la oportunidad de eliminar la palabra clave auto y reemplazarla con el tipo completo de la variable:

const int* const temp = myClass.test();

Al probar todo de nuevo, los resultados fueron los esperados y esta vez no pude reasignar el puntero a una nueva dirección.

Así que después de todo eso supongo que mi pregunta es, ¿por qué? ¿Por qué la palabra clave auto le permite omitir el calificador const de punteros? ¿Hice algo mal?

Por cierto, no estoy seguro de si es importante pero estoy usando la vista previa de Visual Studio 2015


Como ya se mencionó, auto ignora los calificadores cv de nivel superior. Lea este artículo para conocer los detalles de cómo funcionan el auto y el decltype .

Ahora, incluso si auto no ignoró la const , en su caso, la temp todavía no sería const porque los calificadores cv de nivel superior en los tipos de devolución se ignored si el tipo que se devuelve no es de clase.

g ++ incluso produce la siguiente advertencia con -Wextra

advertencia: los calificadores de tipo ignorados en la función devuelven el tipo [-Wignored-qualifiers]

Esto se puede demostrar utilizando el decltype(auto) C ++ 14 decltype(auto) . A diferencia de auto , decltype(auto) no descarta las referencias y los calificadores cv de nivel superior. Si modifica su ejemplo agregando las siguientes líneas, el código aún se compilará, demostrando que la temp no es un puntero const .

decltype(auto) temp = myClass.test(); static_assert(std::is_same<const int*, decltype(temp)>{}, "");

Por otro lado, si test() devuelve un objeto de tipo de clase con un calificador cv de nivel superior, entonces el auto aún descartará const , pero decltype(auto) no.

Demo en vivo


Cuando escribes

auto temp = rhs;

La deducción de tipo funciona de la siguiente manera:

  • Si rhs es una referencia, entonces la referencia se ignora.

  • los calificadores cv (constatable) de nivel superior de rhs también se ignoran (no se ignoran, sin embargo, si lo hace auto& temp = rhs; rhs;; en este caso, el patrón del compilador coincide con el tipo)

En su caso, el tipo del lado derecho es

const int* const ^^^^^ top-level cv qualifier

es decir, puntero de const int - int . El puntero es como cualquier otra variable, por lo que se descartará su constancia (técnicamente, el calificador cv de nivel superior es const y se descartará), por lo tanto, el tipo de temp se deducirá como

const int*

es decir, un puntero no const a const , por lo que se puede volver a asignar. Si desea hacer cumplir la constancia, debe declarar el lado izquierdo como

const auto temp = myClass.test(); ^^^^^ need this

Scott Meyers tiene una excelente introducción al tema (también disponible en su libro Effective Modern C ++ , Ítems 1 y 2 gratis para navegar here ), en el que explica cómo funciona la deducción de tipo de template . Una vez que entiendas eso, entender el modo auto es muy fácil, ya que auto deducción de tipo de auto realmente imita muy de cerca el sistema de deducción de tipo de plantilla (con la notable excepción de std::initializer_list<> ).

EDITAR

Hay una regla adicional para

auto&& temp = rhs;

pero para entenderlo, es necesario comprender cómo funcionan las referencias de reenvío (universales) y cómo funciona el colapso de referencias .


La razón es que auto variables auto no son const por defecto. El hecho de que devuelva el valor const no significa que deba asignarse a una variable const ; el valor se copia después de todo (aunque el valor es un puntero). Puedes intentarlo fácilmente con especificación de tipo explícita también. El valor almacenado en myClass no se cambiará al cambiar la temp variable y el objetivo del puntero sigue siendo const por lo que aún se mantiene la constancia.


Proporcionaré una explicación formal del Estándar para ese hecho para los buscadores de referencia estándar:

La sección N4296::7.1.6.4/7 [dcl.spec.auto]

Si el marcador de posición es el especificador automático de tipo, el tipo deducido se determina utilizando las reglas para la deducción de argumentos de plantilla.

Ahora, el argumento de plantilla dedcution N4296::14.8.2/3 [temp.deduct] :

Se realizan los ajustes de tipo de parámetro de función descritos en 8.3.5.

Y finalmente N4296::8.3.5/5 [dcl.fct]

Después de determinar el tipo de cada parámetro, cualquier parámetro del tipo "matriz de T" o "función que devuelve T" se ajusta para que sea "puntero a T" o "puntero a función que devuelve T", respectivamente. Después de generar la lista de tipos de parámetros, todos los calificadores cv de nivel superior que modifican un tipo de parámetro se eliminan al formar el tipo de función .

En resumen, sí, los calificadores de CV se ignoran en ese caso.