versiones guia español actualizar c++ types c++11 type-inference auto

guia - ¿Cuánto es demasiado con la palabra clave auto C++ 11?



qgis español (14)

Creo que uno debería usar la palabra clave auto cuando sea difícil decir cómo escribir el tipo a primera vista, pero el tipo del lado derecho de una expresión es obvio. Por ejemplo, usando:

my_multi_type::nth_index<2>::type::key_type::composite_key_type::/ key_extractor_tuple::tail_type::head_type::result_type

para obtener el tipo de clave compuesta en boost::multi_index , aunque sepa que es int . No se puede escribir int porque podría cambiarse en el futuro. Yo escribiría auto en este caso.

Entonces, si la palabra clave auto mejora la legibilidad en un caso particular, entonces utilícela. Puede escribir auto cuando es obvio para el lector qué tipo de auto representa.

Aquí hay unos ejemplos:

auto foo = std::make_shared<Foo>(); // obvious auto foo = bla(); // unclear. don''t know which type `foo` has const size_t max_size = 100; for ( auto x = max_size; x > 0; --x ) // unclear. could lead to the errors // since max_size is unsigned std::vector<some_class> v; for ( auto it = v.begin(); it != v.end(); ++it ) // ok, since I know // that `it` has an iterator type (don''t really care which one in this context)

He estado usando la nueva palabra clave auto disponible en el estándar C ++ 11 para tipos de plantilla complicados, para lo cual creo que fue diseñada. Pero también lo estoy usando para cosas como:

auto foo = std::make_shared<Foo>();

Y más escépticamente por:

auto foo = bla(); // where bla() return a shared_ptr<Foo>

No he visto mucha discusión sobre este tema. Parece que el auto podría ser usado en exceso, ya que un tipo es a menudo una forma de documentación y controles de validez. ¿Dónde dibuja la línea en auto y cuáles son los casos de uso recomendados para esta nueva función?

Para aclarar: no estoy pidiendo una opinión filosófica; Solicito el uso previsto de esta palabra clave por parte del comité estándar, posiblemente con comentarios sobre cómo se realiza ese uso previsto en la práctica.

Nota al margen: Esta pregunta se movió a los programadores de SE. y luego de nuevo a Desbordamiento de pila. La discusión sobre esto se puede encontrar en esta meta pregunta .


En C ++ y más allá de 2012 en el panel Pregúntanos todo , hubo un intercambio fantástico entre Andrei Alexandrescu, Scott Meyers y Herb Sutter que hablaban sobre cuándo usar y no usar auto . Salta al minuto 25:03 para una discusión de 4 minutos. Los tres altavoces dan excelentes puntos que deben tenerse en cuenta para cuándo no usar el auto .

Animo encarecidamente a las personas a llegar a su propia conclusión, pero mi retiro fue usar el auto todas partes a menos que :

  1. Duele la legibilidad
  2. Existe preocupación por la conversión automática de tipos (por ejemplo, de constructores, asignación, tipos intermedios de plantilla, conversión implícita entre anchos de enteros)

El uso liberal de lo explicit ayuda a reducir la preocupación por lo último, lo que ayuda a minimizar la cantidad de tiempo que el primero es un problema.

Replanteando lo que Herb dijo, "si no estás haciendo X, Y y Z, usa auto . Aprende qué son X, Y y Z y sigue adelante y usa auto cualquier otro lugar".


Fácil. Úsalo cuando no te importe cuál es el tipo. Por ejemplo

for (const auto & i : some_container) { ...

Todo lo que me importa aquí es que i sea ​​lo que sea que esté en el contenedor.

Es un poco como typedefs.

typedef float Height; typedef double Weight; //.... Height h; Weight w;

Aquí, no me importa si h y w son flotadores o dobles, solo que son del tipo que sea adecuado para expresar alturas y pesos .

O considerar

for (auto i = some_container .begin (); ...

Aquí todo lo que me importa es que es un iterador adecuado, que soporta operator++() , es algo así como escribir pato a este respecto.

Además, el tipo de lambdas no se puede escribir, así que auto f = []... es un buen estilo. La alternativa es lanzar a std::function pero eso viene con gastos generales.

Realmente no puedo concebir un "abuso" de auto . Lo más cercano que puedo imaginar es privarme de una conversión explícita a algún tipo significativo, pero no usaría auto para eso, construiría un objeto del tipo deseado.

Si puede eliminar cierta redundancia en su código sin introducir efectos secundarios, debe ser bueno hacerlo.

Contraejemplos (tomados de las respuestas de otra persona):

auto i = SomeClass(); for (auto x = make_unsigned (y); ...)

Aquí nos importa el tipo, por lo que deberíamos escribir Someclass i; y for(unsigned x = y;...


Sí, se puede utilizar en exceso en detrimento de la legibilidad. Sugiero usarlo en los contextos donde los tipos exactos son largos, inutilizables, o no importantes para la legibilidad, y las variables son de corta duración. Por ejemplo, el tipo de iterador generalmente es largo y no es importante, por lo que el auto funcionaría:

for(auto i = container.begin(); i != container.end(); ++i);

Aquí el auto no daña la legibilidad.

Otro ejemplo es el tipo de regla del analizador, que puede ser largo y complicado. Comparar:

auto spaces = space & space & space;

con

r_and_t<r_and_t<r_char_t<char>&, r_char_t<char>&>, r_char_t<char>&> spaces = space & space & space;

Por otro lado, cuando el tipo es conocido y es simple, es mucho mejor si se establece explícitamente:

int i = foo();

más bien que

auto i = foo();


Un peligro que he notado es en términos de referencias. p.ej

MyBigObject& ref_to_big_object= big_object; auto another_ref = ref_to_big_object; // ?

El problema es que another_ref no es realmente una referencia en este caso es MyBigObject en lugar de MyBigObject &. Terminas copiando un objeto grande sin darte cuenta.

Si obtiene una referencia directamente de un método, es posible que no piense en lo que realmente es.

auto another_ref = function_returning_ref_to_big_object();

necesitarías "auto &" o "const auto &"

MyBigObject& ref_to_big_object= big_object; auto& another_ref = ref_to_big_object; const auto& yet_another_ref = function_returning_ref_to_big_object();


Una de mis experiencias amargas con auto es usarlo con expresiones lambda :

auto i = []() { return 0; }; cout<<"i = "<<i<<endl; // output: 1 !!!

En realidad, aquí se resuelve el puntero de función de int(*)() . Esto es solo un cout simple, pero imagínese qué tipo de errores de compilación / tiempo de ejecución incorrectos puede causar cuando se usa con la template .

Debería evitar el auto con tales expresiones y poner un tipo de return adecuado (o tipo de control controlado decltype() )

El uso correcto para el ejemplo anterior sería,

auto i = []() { return 0; }(); // and now i contains the result of calling the lambda


Uno de los principales problemas con el programa C ++ es que le permite usar la variable sin inicializar . Esto nos lleva al comportamiento desagradable del programa no determinista. Se debe tener en cuenta que el compilador moderno ahora envía mensajes de advertencia apropiados / mensajes si el programa se cansa de usarlo.

Solo para ilustrar esto, considere el siguiente programa c ++:

int main() { int x; int y = 0; y += x; }

Si compilo este programa usando el compilador moderno (GCC), da la advertencia. Tal advertencia puede no ser muy obvia si estamos trabajando con el código de producción complejo real.

main.cpp: En la función ''int main ()'':

main.cpp: 4: 8: advertencia : ''x'' se usa sin inicializar en esta función [-Wuninitialized]

y + = x;

^

================================================== =============================== Ahora, si cambiamos nuestro programa que usa auto , luego compilamos obtenemos lo siguiente:

int main() { auto x; auto y = 0; y += x; }

main.cpp: En la función ''int main ()'':

main.cpp: 2: 10: error : la declaración de ''auto x'' no tiene inicializador

auto x; ^

Con auto, no es posible usar la variable sin inicializar. Esta es la principal ventaja que podemos obtener (gratis), si empezamos a utilizar el modo automático .

Herb Shutter, experto en C ++, explica este concepto y otro gran concepto moderno de C ++ en su charla sobre CppCon14 :

¡De vuelta a lo fundamental! Elementos esenciales del estilo moderno de C ++


Use auto donde tenga sentido para inferir un tipo. Si tiene algo que sabe que es un número entero, o sabe que es una cadena, simplemente use int / std :: string, etc. No me preocuparía "abusar" de una función de idioma a menos que llegue al punto de ridiculez, u ofusca el código.

Esa es mi opinión de todos modos.


Use el auto todos los lugares que pueda, particularmente el modo const auto modo que los efectos secundarios sean menos preocupantes. No tendrá que preocuparse por los tipos, excepto en los casos obvios, pero aún así serán verificados estáticamente para usted, y puede evitar algunas repeticiones. Cuando el auto no es factible, puede usar decltype para expresar tipos semánticamente como contratos basados ​​en expresiones. Su código se verá diferente, pero será un cambio positivo.


Uso auto sin restricción y no tuve ningún problema. Incluso a veces termino usándolo para tipos simples como int . Esto hace que c ++ sea un lenguaje de nivel superior para mí, y permite declarar variables en c ++ como en python. Después de escribir el código de Python, incluso a veces escribo por ejemplo

auto i = MyClass();

en lugar de

MyClass i;

Este es un caso donde diría que es un abuso de la palabra clave auto .

A menudo no me importa cuál es el tipo exacto del objeto, me interesa más su carácter funcional y, como los nombres de las funciones generalmente dicen algo acerca de los objetos que devuelven, el auto no duele: en, por ejemplo, auto s = mycollection.size() , Puedo adivinar que s será un tipo de entero, y en el raro caso de que me importe el tipo exacto, entonces verifiquemos la función del prototipo (quiero decir, prefiero tener que verificar cuando necesito la información, en lugar de a priori cuando se escribe el código, por si acaso sería útil algún día, como en int_type s = mycollection.size() ).

Respecto a este ejemplo de la respuesta aceptada:

for ( auto x = max_size; x > 0; --x )

En mi código, todavía uso auto en este caso, y si quiero que x no esté firmado, entonces uso una función de utilidad, llamada say make_unsigned , que expresa claramente mis preocupaciones:

for ( auto x = make_unsigned(max_size); x > 0; --x )

descargo de responsabilidad: acabo de describir mi uso, no soy competente para dar consejos!


Ve a por ello. Utiliza el auto cualquier lugar, lo que facilita la escritura de código.

Cada nueva característica en cualquier idioma será utilizada en exceso por al menos algunos tipos de programadores. Es solo a través de un uso excesivo moderado por parte de algunos programadores experimentados (no noobs) que el resto de los programadores experimentados aprenden los límites del uso adecuado. El uso excesivo extremo suele ser malo, pero podría ser bueno porque dicho uso excesivo puede llevar a mejoras en la función o una mejor función para reemplazarla.

Pero si estuviera trabajando en código con más de unas pocas líneas como

auto foo = bla();

donde el tipo se indica cero veces, es posible que desee cambiar esas líneas para incluir tipos. El primer ejemplo es excelente ya que el tipo se indica una vez, y el ahorro auto nos obliga a tener que escribir tipos de plantilla desordenados dos veces. Hurra por C ++++. Pero mostrar explícitamente el tipo cero veces, si no es fácilmente visible en una línea cercana, me pone nervioso, al menos en C ++ y sus sucesores inmediatos. Para otros lenguajes diseñados para trabajar en un nivel superior con más abstracción, polimorfismo y genérico, está bien.


auto palabra clave auto solo se puede usar para variables locales, no para argumentos o miembros de clase / estructura. Por lo tanto, es seguro y viable utilizarlos en cualquier lugar que desee. Yo los uso mucho. El tipo se deduce en el momento de la compilación, el depurador muestra el tipo mientras realiza la depuración, el sizeof informa correctamente, el tipo de decltype daría el tipo correcto, no hay daño. ¡No cuento el auto como usado en exceso, nunca!


auto puede ser muy peligroso en combinación con las plantillas de expresión que se utilizan mucho en las bibliotecas de álgebra lineal, como Eigen o OpenCV.

auto A = Matrix(...); auto B = Matrix(...); auto C = A * B; // C is not a matrix. It is a matrix EXPRESSION. cout << C; // The expression is evaluated and gives the expected result. ... // <code modifying A or B> cout << C; // The expression is evaluated AGAIN and gives a DIFFERENT result.

Los errores causados ​​por este tipo de errores son un gran problema para depurar. Una posible solución es emitir explícitamente el resultado al tipo esperado si está empeñado en utilizar el modo automático para el estilo de declaración de izquierda a derecha.

auto C = Matrix(A * B); // The expression is now evaluated immediately.


TL; DR: Ver la regla de oro en la parte inferior.

La respuesta aceptada sugiere la siguiente regla de oro:

Use auto cuando sea difícil decir cómo escribir el tipo a primera vista, pero el tipo del lado derecho de una expresión es obvio.

Pero diría que eso es demasiado restrictivo. En algún momento no me importan los tipos, ya que la declaración es lo suficientemente informativa sin que me moleste en tomarme el tiempo para averiguar el tipo. ¿Qué quiero decir con eso? Considere el ejemplo que ha aparecido en algunas de las respuestas:

auto x = f();

¿Qué hace esto un ejemplo de mal uso de auto ? ¿Es mi ignorancia del tipo de retorno de f() ? Bueno, de hecho podría ayudar si lo supiera, pero esa no es mi principal preocupación. Lo que es mucho más problemático es que x y f() carecen de sentido. Si tuvieramos:

auto nugget = mine_gold();

en cambio, generalmente no me importa si el tipo de retorno de la función es obvio o no. Al leer el enunciado, sé lo que estoy haciendo y sé lo suficiente sobre la semántica del valor de retorno para no sentir que necesito saber también su tipo.

Así que mi respuesta es: use auto siempre que el compilador lo permita, a menos que:

  • Siente que el nombre de la variable junto con la expresión de inicialización / asignación no proporciona suficiente información sobre lo que está haciendo la declaración.
  • Siente que el nombre de la variable junto con la expresión de inicialización / asignación proporciona información "engañosa" sobre cuál debería ser el tipo, es decir, si tuviera que adivinar lo que viene en lugar del auto, podría hacer una conjetura, y sería mal, y esta suposición falsa tiene repercusiones más adelante en el código.
  • Desea forzar un tipo diferente (por ejemplo, una referencia).

Y también:

  • Prefiere dar un nombre significativo (que no contenga el nombre de tipo, por supuesto) antes de reemplazar el auto con el tipo concreto.