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


He estado usando la nueva palabra clave auto disponible en el estándar de C++11 para tipos de plantillas complicadas, que es para lo que 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 para:

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

No he visto mucha discusión sobre este tema. Parece que auto podría ser usado en exceso, ya que un tipo es a menudo una forma de documentación y comprobaciones de cordura. ¿Dónde se traza la línea al usar auto y cuáles son los casos de uso recomendados para esto nueva característica?

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

Nota al margen: Esta pregunta fue trasladada al SE.Programadores y luego de nuevo a la pila de desbordamiento. La discusión sobre esto se puede encontrar en esta meta pregunta .

Author: Jarod42, 2011-06-22

14 answers

Creo que uno debería usar la palabra clave auto siempre que 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 la clave compuesta escriba boost::multi_index, aunque sepa que es int. No puedes simplemente escribir int porque podría ser cambiado en el futuro. Yo escribiría auto en este caso.

Así que si la palabra clave auto mejora la legibilidad en un caso particular, entonces úsala. Puede escribir auto cuando sea obvio para el lector qué tipo representa auto.

Aquí hay algunos 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)
 114
Author: Kirill V. Lyadvinsky,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-07-04 00:07:34

Use auto en todas partes, en particular const auto para que los efectos secundarios sean menos preocupantes. No tendrá que preocuparse por los tipos excepto en los casos obvios, pero aún así se verificarán estáticamente para usted, y puede evitar cierta repetición. Donde auto no es factible, puede usar decltype para expresar los tipos semánticamente como contratos basados en expresiones. Su código se verá diferente, pero será un cambio positivo.

 53
Author: Jon Purdy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-03-31 04:24:19

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 es lo que hay 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 cualquier tipo que sea adecuado para expresar alturas y pesos.

O considere

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

Aquí todo lo que me importa es que es un iterador adecuado, apoyando operator++(), es algo así como escribir pato en este sentido.

También el tipo de lambdas no se puede deletrear, por lo 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 privarse de una conversión explícita a algún tipo -- pero usted no se utilice auto para que, tendría que construir un objeto del tipo deseado.

Si can elimine cierta redundancia en su código sin introducir efectos secundarios, entonces debe sería bueno hacerlo.

Contraejemplos (tomados de las respuestas de otra persona):

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

Aquí nos importa cuál es el tipo, por lo que debemos escribir Someclass i; y for(unsigned x = y;...

 43
Author: spraff,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-10-30 12:15:17

Adelante. Use auto en cualquier lugar que facilite la escritura de código.

Cada nueva característica en cualquier lenguaje va a ser sobreutilizada por al menos algunos tipos de programadores. Es solo a través del uso excesivo moderado por algunos programadores experimentados (no noobs) que el resto de los programadores experimentados aprenden los límites del uso adecuado. El uso excesivo extremo generalmente es malo, pero podría ser bueno porque tal uso excesivo puede conducir a mejoras en la función o una mejor función para reemplazar se.

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 genial ya que el tipo se indica una vez, y auto nos evita tener que escribir tipos de plantillas desordenadas 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 a un nivel superior con más abstracción, polimorfismo y genericidad, está bien.

 40
Author: DarenW,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-26 07:49:40

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

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

auto aquí no perjudica la legibilidad.

Otro ejemplo es el tipo de regla parser, que puede ser larga y enrevesada. 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 otra parte, cuando el tipo es conocido y es simple, es mucho mejor si se indica explícitamente:

int i = foo();

En lugar de

auto i = foo();
 35
Author: Gene Bushuyev,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-06-22 04:56:36

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

Animo mucho a la gente a llegar a su propia conclusión, pero mi conclusión fue usar auto en todas partes a menos que:

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

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

Reformulando lo que Herb dijo, "si no estás haciendo X, Y y Z, usa auto. Aprende qué son X, Y y Z y seguir adelante y usar auto en todas partes."

 32
Author: Sean,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-04-08 17:37:27

auto puede ser muy peligroso en combinación con plantillas de expresión que son utilizadas mucho por bibliotecas de álgebra lineal como Eigen u 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. Un posible remedio es convertir explícitamente el resultado al tipo esperado si está empeñado en usar auto para el estilo de declaración de izquierda a derecha.

auto C = Matrix(A * B); // The expression is now evaluated immediately.
 15
Author: morotspaj,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-02-20 20:50:58

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

auto i = MyClass();

En lugar de

MyClass i;

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

A menudo no me importa cuál es el tipo exacto del objeto, estoy más interesado en su funcionalidad, y como los nombres de las funciones generalmente dicen algo sobre los objetos que devuelven, auto no hace daño: por ejemplo, auto s = mycollection.size(), puedo adivinar que s será una especie de entero, y en el raro caso en el que me importa el tipo exacto, comprobemos el prototipo de la función entonces (es decir, prefiero tener que verificar cuando necesito la información, en lugar de a priori cuando se escribe el código, por si acaso algún día sería útil, como en int_type s = mycollection.size()).

Con respecto a este ejemplo de la aceptada respuesta:

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

En mi código todavía uso auto en este caso, y si quiero x que 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!

 8
Author: rafak,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-06-22 15:09:26

Un peligro que he observado es en términos de referencias. por ejemplo,

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

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

Si está obteniendo 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á " 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();
 2
Author: user2495422,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-02-21 06:04:28

Uno de los mayor problema con el programa C++ es que le permite utilizar el variable no inicializada. Esto nos lleva a un comportamiento desagradable no determinista del programa. Cabe señalar que el compilador moderno ahora lanza 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 no puede ser muy obvio si estamos trabajando con el código de producción complejo real.

Main.cpp: In function ' 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 utiliza auto, luego compilamos lo siguiente:

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

Main.cpp: In function ' 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 no inicializada. Esta es una gran ventaja que podemos obtener (de forma gratuita), si comenzamos a usar auto.

Este concepto y otro gran concepto moderno de C++ es explicado por el experto en C++ Herb Shutter en su CppCon14 charla:

¡Volvamos a lo básico! Elementos esenciales del Estilo C++ Moderno

 2
Author: Mantosh Kumar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-10-02 21:39:16

Use auto cuando tenga sentido inferir un tipo. Si tienes algo que sabes que es un entero,o sabes que es una cadena, simplemente usa int / std:: string, etc. No me preocuparía por "abusar" de una característica del lenguaje a menos que llegue al punto de ridiculez u ofusque el código.

Esa es mi opinión de todos modos.

 1
Author: LainIwakura,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-06-22 04:52:36

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

 1
Author: Ajay,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-06-22 16:12:38

TL; DR: Ver regla general en la parte inferior.

La respuesta aceptada sugiere la siguiente regla empírica:

Use auto siempre que 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 yo diría que eso es demasiado restrictivo. A veces no me importan los tipos, ya que la declaración es lo suficientemente informativa sin que me moleste en tomarme el tiempo para calcular el tipo fuera. ¿Qué quiero decir con eso? Considere el ejemplo que ha aparecido en algunas de las respuestas:

auto x = f();

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

auto nugget = mine_gold();

En cambio, entonces generalmente no me importa si el tipo de retorno de la función es obvio o no. Leyendo el declaración, sé lo que estoy haciendo y sé lo suficiente sobre lo que 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:

  • Cree que el nombre de la variable junto con la expresión de inicialización / asignación no proporcionan suficiente información sobre lo que está haciendo la instrucció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 tuvieras que adivinar lo que viene en lugar del auto, podrías hacer una conjetura - y sería incorrecta, 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:

  • Prefiera dar un nombre significativo (que no contenga el nombre del tipo, por supuesto) antes de reemplazar auto con el tipo concreto.
 0
Author: einpoklum,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-02-27 10:40:56

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

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

En realidad, aquí i se resuelve como 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 template.

Debes evitar auto con tales expresiones y poner un tipo propio return (o 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  
 -3
Author: iammilind,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-06-22 06:22:26