He estado usando la nueva auto
palabra clave disponible en el estándar C ++ 11 para tipos de plantillas 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 auto
podría usarse en exceso, ya que un tipo es a menudo una forma de documentación y controles de sanidad. ¿Dónde trazas la línea de uso auto
y cuáles son los casos de uso recomendados para esta nueva característica?
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 trasladó a SE.Programmers y luego a Stack Overflow. La discusión sobre esto se puede encontrar en esta meta pregunta .
auto
palabra clave, entonces sabes cómo se supone que debe usarse. Eso es lo que pregunto, como alguien que es nuevo en esta función, ¿cómo se supone que debo usarla?var
(es decir, una vez que la gente superó la idea de que no era una escritura dinámica después de todo). Si lo desea, puede comenzar con esta pregunta y pasar por las preguntas relacionadas.auto foo = bla();
"malo" es claramente una opinión, no un hecho, lo que hace esta pregunta y responde a una discusión, lo que la hace relevante para los Programadores SE, que es exactamente lo que indican los votos cerrados. / encogimiento de hombrosRespuestas:
Creo que uno debe usar la
auto
palabra clave 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:para obtener el tipo de clave compuesta
boost::multi_index
, aunque sepa que es asíint
. No puedes simplemente escribirint
porque podría cambiarse en el futuro. Yo escribiríaauto
en este caso.Entonces, si la
auto
palabra clave mejora la legibilidad en un caso particular, úsela. Puede escribirauto
cuando sea obvio para el lector qué tipoauto
representa.Aquí hay unos ejemplos:
fuente
bla()
regrese se lo estás dandofoo
.Úselo
auto
donde pueda, especialmenteconst auto
para que los efectos secundarios sean menos preocupantes. No tendrá que preocuparse por los tipos, excepto en los casos obvios, pero todavía serán verificados estáticamente por usted y puede evitar algunas repeticiones. Dondeauto
no sea factible, puede usarlodecltype
para expresar tipos semánticamente como contratos basados en expresiones. Su código se verá diferente, pero será un cambio positivo.fuente
auto&&
en situaciones complejas edmundv.home.xs4all.nl/blog/2014/01/28/…const auto&
o, aconst auto
menos que explícitamente, quiera mutar o mover.auto str = std::string();
lugar destd::string str;
?Fácil. Úselo cuando no le importa cuál es el tipo. Por ejemplo
Todo lo que me importa aquí es que
i
sea lo que haya en el contenedor.Es un poco como typedefs.
En este caso, no me importa si
h
yw
son flotadores o dobles, sólo que son cualquier tipo es adecuado para expresar alturas y pesos .O considerar
Aquí todo lo que me importa es que es un iterador adecuado, compatible
operator++()
, es como escribir un pato a este respecto.Además, el tipo de lambdas no se puede deletrear, por lo que
auto f = []...
es un buen estilo. La alternativa es emitirstd::function
pero eso viene con gastos generales.Realmente no puedo concebir un "abuso" de
auto
. Lo más cercano que puedo imaginar es privarte de una conversión explícita a algún tipo significativo, pero no lo usaríasauto
para eso, construirías un objeto del tipo deseado.Si puede eliminar algo de redundancia en su código sin introducir efectos secundarios, entonces debe ser bueno hacerlo.
Contraejemplos (tomados de las respuestas de otra persona):
Aquí nos importa cuál es el tipo, por lo que debemos escribir
Someclass i;
yfor(unsigned x = y;...
fuente
auto
.Ve a por ello. Úselo en
auto
cualquier lugar que facilite 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 del uso excesivo moderado por algunos programadores experimentados (no novatos) 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 conducir 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
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
auto
nos ahorra tener que escribir dos tipos de plantillas desordenadas. ¡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.fuente
En C ++ y más allá de 2012 en el panel Ask Us Anything , hubo un intercambio fantástico entre Andrei Alexandrescu, Scott Meyers y Herb Sutter hablando sobre cuándo usar y no usar
auto
. Pase al minuto 25:03 para una discusión de 4 minutos. Los tres altavoces ofrecen excelentes puntos que deben tenerse en cuenta para cuándo no usarauto
.Recomiendo encarecidamente a las personas que lleguen a su propia conclusión, pero mi objetivo fue usarlo en
auto
todas partes a menos que :El uso liberal de
explicit
ayuda a reducir la preocupación por el segundo, lo que ayuda a minimizar la cantidad de tiempo que el primero es un problema.Reformulando lo que dijo Herb, "si no estás haciendo X, Y y Z, usa
auto
. Aprende qué son X, Y y Z y ve y usa enauto
todas partes".fuente
Sí, se puede usar en exceso en detrimento de la legibilidad. Sugiero usarlo en los contextos donde los tipos exactos son largos, indescifrables 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
auto
lo que funcionaría:auto
aquí no hace daño a la legibilidad.Otro ejemplo es el tipo de regla del analizador, que puede ser largo y complicado. Comparar:
con
Por otro lado, cuando se conoce el tipo y es simple, es mucho mejor si declara explícitamente:
más bien que
fuente
begin()
yend()
, o el tamaño de tu paso es diferente a uno, o estás modificando el contenedor a medida que avanzas, la declaración basada en el rango no te ayudará.r_and_t<r_and_t<r_char_t<char>&, r_char_t<char>&>, r_char_t<char>&>
hace?space
es y buscarlo. Esa es la información más útil de todos modos ... después de todo, el problema no es "¿qué tipo es esta nueva variable" sino más bien "quéspace & space & space
significa?" El tipo real de la expresión es solo ruido.auto
puede ser muy peligroso en combinación con plantillas de expresión que se usan mucho en bibliotecas de álgebra lineal como Eigen u OpenCV.Los errores causados por este tipo de errores son un gran dolor para depurar. Un posible remedio es emitir explícitamente el resultado al tipo esperado si está empeñado en usar auto para el estilo de declaración de izquierda a derecha.
fuente
A*B
expresión se copie o no en unaauto
variable o en otra cosa, el comportamiento que usted describe sigue presente.auto
.diag(A * B)
, no tiene que desperdiciar ciclos calculando los elementos fuera de la diagonal.Utilizo
auto
sin restricción y no tuve ningún problema. Incluso a veces termino usándolo para tipos simples comoint
. 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 ejemploen vez de
Este es un caso en el que diría que es un abuso de la
auto
palabra clave.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 duele: por ejemploauto s = mycollection.size()
, puedo suponer ques
será una especie de número entero, y en el raro caso en que me preocupe el tipo exacto, verifiquemos el prototipo de la función (quiero decir, prefiero tener que verificar cuando necesito la información, en lugar de a priori cuando se escribe el código, solo en caso de que sea útil algún día, como enint_type s = mycollection.size()
).Con respecto a este ejemplo de la respuesta aceptada:
En mi código todavía lo uso
auto
en este caso, y si quierox
estar sin firmar, entonces uso una función de utilidad, llamada saymake_unsigned
, que expresa claramente mis preocupaciones:Descargo de responsabilidad: ¡acabo de describir mi uso, no soy competente para dar consejos!
fuente
auto i = MyClass()
.as_unsigned
se recomienda allí, o inclusoauto w = widget{};
.Uno de los principales problemas con el programa C ++ es que le permite usar la variable no inicializada . Esto nos lleva a un comportamiento desagradable del programa no determinista. Cabe señalar que el compilador moderno ahora arroja mensajes de advertencia apropiados / mensaje si el programa se cansa de usarlo.
Solo para ilustrar esto, considere el siguiente programa c ++:
Si compilo este programa usando el compilador moderno (GCC), me da la advertencia. Tal advertencia puede no ser muy obvia si estamos trabajando con el código de producción complejo real.
================================================== =============================== Ahora si cambiamos nuestro programa que usa auto , compilamos y obtenemos lo siguiente:
Con auto, no es posible usar la variable no inicializada. Esta es una gran ventaja que podemos obtener (gratis), si comenzamos a usar auto .
Este concepto y otro gran gran concepto moderno de C ++ es explicado por Herb Shutter, experto en C ++, en su charla CppCon14 :
¡De vuelta a lo basico! Elementos esenciales del estilo moderno de C ++
fuente
auto
.auto
, pero no lo necesita para abordar este problema.Un peligro que he notado es en términos de referencias. p.ej
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 qué es realmente.
necesitaría "auto &" o "const auto &"
fuente
Use
auto
donde tenga sentido que se infiera 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 por "usar en exceso" una característica del lenguaje a menos que llegue al punto de ridículo, u ofusca el código.Esa es mi opinión de todos modos.
fuente
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 el momento de la compilación, el depurador muestra el tipo durante la depuración, losizeof
informa correctamente,decltype
daría el tipo correcto, no hay daño. ¡No cuentoauto
como sobreutilizado, nunca!fuente
TL; DR: Vea la regla general en la parte inferior.
La respuesta aceptada sugiere la siguiente regla general:
Pero yo diría que 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 resolver el tipo. ¿Qué quiero decir con eso? Considere el ejemplo que ha aparecido en algunas de las respuestas:
¿Qué hace de esto un ejemplo de mal uso de
auto
? ¿Es mi ignorancia delf()
tipo de retorno de? Bueno, de hecho puede ayudar si lo supiera, pero esa no es mi principal preocupación. Lo que es un problema mucho mayor es esox
y nof()
tienen mucho sentido. Si tuvieramos:en cambio, generalmente no me importa si el tipo de retorno de la función es obvio o no. Al leer la declaración, 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.
Entonces mi respuesta es: usar
auto
siempre que el compilador lo permita, a menos que:Y también:
auto
por el tipo concreto.fuente
Una de mis amargas experiencias
auto
es usarlo con expresiones lambda :En realidad, aquí
i
se resuelve funcionar el puntero deint(*)()
. Esto es simplecout
, pero imagínese qué tipo de errores de compilación / tiempo de ejecución incorrectos puede causar cuando se usatemplate
.Debe evitar
auto
con tales expresiones y poner unreturn
tipo apropiado (o controladodecltype()
)El uso correcto para el ejemplo anterior sería,
fuente
()
al final. Las lambdas están ahí para actuar como funciones y de ahí proviene la conversión del puntero de función. Si quieres llamarlo de inmediato, ¿por qué usar una lambda?auto i = 0;
Funciona bastante bien.auto x = []() { /* .... whatever goes in here ... */ }()
es mejor queauto x = /* .... whatever goes in here ... */;
, es decir, lo mismo, sin la lambda? Me parece bastante inútil, por la misma razón noauto x = 42 + y - 42
tiene sentido.