Con el nuevo estándar, hay nuevas formas de hacer las cosas, y muchas son mejores que las antiguas, pero la forma antigua sigue estando bien. También está claro que el nuevo estándar no se desaprueba mucho oficialmente, por razones de compatibilidad con versiones anteriores. Entonces la pregunta que queda es:
¿Qué antiguas formas de codificación son definitivamente inferiores a los estilos de C++ 11 y qué podemos hacer ahora en su lugar?
Al responder esto, puede omitir las cosas obvias como “usar variables automáticas”.
Ya no se recomienda devolver valores constantes. Obviamente auto_ptr también está en desuso.
– KerrekSB
15 de febrero de 2012 a las 18:38
Por supuesto que puedes, Pubby. Antes de que se inventaran las plantillas de C++, existía una técnica de macros para crear plantillas. Luego, C ++ los agregó, y la forma anterior se consideró mala.
– Alan Baljeu
15 de febrero de 2012 a las 18:41
Esta pregunta realmente debe trasladarse a Programmers.se.
– Nicolás Bolas
15 de febrero de 2012 a las 19:11
Sumante
Clase final: C++11 proporciona la final especificador para evitar la derivación de clases
Las lambdas de C++11 reducen sustancialmente la necesidad de clases de objetos de función con nombre (funtores).
Constructor de movimiento: Las formas mágicas en las que std::auto_ptr las obras ya no son necesarias debido al soporte de primera clase para las referencias de rvalue.
bool seguro: Esto se mencionó anteriormente. Los operadores explícitos de C++11 obvian este modismo muy común de C++03.
Encoger para ajustar: Muchos contenedores STL de C++11 proporcionan una shrink_to_fit() miembro de la función, que debería eliminar la necesidad de intercambiar con un temporal.
Clase Base Temporal: Algunas bibliotecas antiguas de C++ utilizan este lenguaje bastante complejo. Con la semántica de movimiento ya no es necesario.
Prohibir la asignación de montones: Los = delete La sintaxis es una forma mucho más directa de decir que se niega explícitamente una funcionalidad en particular. Esto es aplicable para evitar la asignación de montones (es decir, =delete para miembro operator new), impidiendo copias, cesión, etc.
Gran respuesta, pero atacaría. result_of de la lista. A pesar de lo engorroso typename necesario antes, creo typename result_of<F(Args...)::type a veces puede ser más fácil de leer que decltype(std::declval<F>()(std::declval<Args>()...)y con la aceptación de N3436 en el documento de trabajo ambos trabajan para SFINAE (lo que solía ser una ventaja de decltype que result_of no ofreció)
–Jonathan Wakely
18 de enero de 2013 a las 9:17
Con respecto a 14) Todavía estoy llorando porque tengo que usar macros para escribir el mismo código dos veces, una para el cuerpo de la función y otra para la instrucción decltype()…
– usuario678269
31 de marzo de 2014 a las 22:56
Me gustaría señalar que este tema está vinculado desde esta página de Microsoft como un artículo “Para obtener más información” en una introducción general al lenguaje C++, ¡pero este tema es altamente especializado! ¿Puedo sugerir que un breve “¡Este tema NO es para principiantes de C++!” ¿Se incluirán consejos al comienzo del tema o esta respuesta?
– Aacini
11 de abril de 2015 a las 5:41
Re 12: “Inicialización de miembros en clase”: esa es la nueva expresión, no una expresión obsoleta, ¿no? ¿Cambiar el orden de las oraciones tal vez? Re 2: Los funtores son muy útiles cuando desea pasar tipos en lugar de objetos (especialmente en parámetros de plantilla). Entonces es solo alguno usos de funtores que están en desuso.
– einpoklum
17 junio 2016 a las 20:59
En un momento dado se argumentó que uno debería regresar por const valor en lugar de solo por valor:
const A foo();
^^^^^
Esto era en su mayoría inofensivo en C++ 98/03, y es posible que incluso haya detectado algunos errores que se parecían a:
foo() = a;
Pero volviendo por const está contraindicado en C++ 11 porque inhibe la semántica de movimiento:
A a = foo(); // foo will copy into a instead of move into it
Así que relájate y codifica:
A foo(); // return by non-const value
Sin embargo, ahora se pueden detectar los errores evitables mediante el uso de calificadores de referencia para funciones. Tal como en el caso anterior definiendo A& operator=(A o)& en vez de A& operator=(A o). Estos evitan los errores tontos y hacen que las clases se comporten más como tipos básicos y no evitan la semántica de movimiento.
– José
3 de junio de 2013 a las 15:21
Tan pronto como puedas abandonar 0 y NULL a favor de nullptr¡hazlo!
En código no genérico, el uso de 0 o NULL no es gran cosa. Pero tan pronto como comienza a pasar constantes de puntero nulo en código genérico, la situación cambia rápidamente. cuando pasas 0 a un template<class T> func(T)T se deduce como un int y no como una constante de puntero nulo. Y no se puede volver a convertir en una constante de puntero nulo después de eso. Esto cae en cascada en un atolladero de problemas que simplemente no existirían si el universo usara solo nullptr.
C++ 11 no está en desuso 0 y NULL como constantes de puntero nulo. Pero deberías codificar como si lo hiciera.
¿Qué es decltype (nullptr)?
– usuario678269
31 de marzo de 2014 a las 23:02
@GrapschKnutsch: Es std::nullptr_t.
– Howard Hinant
01/04/2014 a las 15:25
Sugiera que esto se reformule como el idioma en desuso en lugar de la nueva convención a adoptar (por ejemplo, “El uso de 0 o NULL para punteros nulos”).
Constructores de copias privadas (boost::noncopyable) → X(const X&) = delete
Simulando clase final con destructor privado y herencia virtual → class X final
Klaim
Una de las cosas que evita escribir algoritmos básicos en C++ 11 es la disponibilidad de lambdas en combinación con los algoritmos proporcionados por la biblioteca estándar.
Los estoy usando ahora y es increíble la frecuencia con la que solo dices lo que quieres hacer usando count_if(), for_each() u otros algoritmos en lugar de tener que escribir los malditos bucles nuevamente.
Una vez que esté utilizando un compilador de C++ 11 con una biblioteca estándar completa de C++ 11, ya no tienes una buena excusa para no usar algoritmos estándar para construir los tuyos. Lambda acaba de matarlo.
¿Por qué?
En la práctica (después de haber usado esta forma de escribir algoritmos yo mismo) se siente mucho más fácil leer algo que está construido con palabras sencillas que significan lo que se hace que con algunos bucles que tienes que descifrar para saber el significado. Dicho esto, hacer que los argumentos lambda se deduzcan automáticamente ayudaría mucho a hacer que la sintaxis sea más fácil de comparar con un bucle sin formato.
Básicamente, los algoritmos de lectura hechos con algoritmos estándar son mucho más fáciles que las palabras que ocultan los detalles de implementación de los bucles.
Supongo que solo se debe pensar en los algoritmos de nivel superior ahora que tenemos algoritmos de nivel inferior para construir.
En realidad hay una buena excusa. estas usando Boost.Rango de algoritmos, que son mucho mejores;)
– Nicolás Bolas
15 de febrero de 2012 a las 18:42
no veo eso for_each con una lambda es mejor que el bucle for equivalente basado en rango, con el contenido de la lambda en el bucle. El código se ve más o menos igual, pero la lambda introduce una puntuación extra. Puedes usar equivalentes de cosas como boost::irange para aplicarlo a más bucles que solo aquellos que obviamente usan iteradores. Además, el bucle for basado en rango tiene una mayor flexibilidad, ya que puede salir antes si es necesario (mediante return o por break), mientras que con for_each tendrías que tirar.
–Steve Jessop
15 de febrero de 2012 a las 18:49
@SteveJessop: Aun así, la disponibilidad de rango basado for hace lo habitual it = c.begin(), const end = c.end(); it != end; ++it modismo desaparecido.
– Ben Voigt
15 de febrero de 2012 a las 19:03
@SteveJessop Una ventaja de la for_each algoritmo sobre el rango basado en bucle es que usted no poderbreak o return. Es decir, cuando ves for_each sabes inmediatamente sin mirar el cuerpo que no hay tal truco.
– bames53
15 de febrero de 2012 a las 19:18
@Klaim: para ser específicos, estoy comparando, por ejemplo std::for_each(v.begin(), v.end(), [](int &i) { ++i; }); con for (auto &i : v) { ++i; }. Acepto que la flexibilidad es de doble filo (goto es muy flexible, ese es el problema). No creo que la restricción de no poder usar break en el for_each versión compensa la verbosidad adicional que exige: los usuarios de for_each Aquí están, en mi opinión, sacrificando la legibilidad y la comodidad reales por una especie de noción teórica de que el for_each es en principio más claro y conceptualmente más simple. En la práctica no es más claro ni más sencillo.
–Steve Jessop
15 de febrero de 2012 a las 19:36
Felipe
Deberá implementar versiones personalizadas de swap con menos frecuencia. En C ++ 03, un no lanzamiento eficiente swap suele ser necesario para evitar copias costosas y tiradas, y dado que std::swap utiliza dos copias, swap a menudo tiene que ser personalizado. En C++, std::swap usos move, por lo que el enfoque cambia en la implementación de constructores de movimiento eficientes y que no lanzan y operadores de asignación de movimiento. Dado que para estos, el valor predeterminado a menudo está bien, será mucho menos trabajo que en C++ 03.
Por lo general, es difícil predecir qué modismos se usarán, ya que se crean a través de la experiencia. Podemos esperar un “C++ 11 efectivo” tal vez el próximo año, y un “C++ 11 Coding Standards” solo en tres años porque aún no se cuenta con la experiencia necesaria.
En realidad hay una buena excusa. estas usando Boost.Rango de algoritmos, que son mucho mejores;)
– Nicolás Bolas
15 de febrero de 2012 a las 18:42
no veo eso for_each con una lambda es mejor que el bucle for equivalente basado en rango, con el contenido de la lambda en el bucle. El código se ve más o menos igual, pero la lambda introduce una puntuación extra. Puedes usar equivalentes de cosas como boost::irange para aplicarlo a más bucles que solo aquellos que obviamente usan iteradores. Además, el bucle for basado en rango tiene una mayor flexibilidad, ya que puede salir antes si es necesario (mediante return o por break), mientras que con for_each tendrías que tirar.
–Steve Jessop
15 de febrero de 2012 a las 18:49
@SteveJessop: Aun así, la disponibilidad de rango basado for hace lo habitual it = c.begin(), const end = c.end(); it != end; ++it modismo desaparecido.
– Ben Voigt
15 de febrero de 2012 a las 19:03
@SteveJessop Una ventaja de la for_each algoritmo sobre el rango basado en bucle es que usted no poderbreak o return. Es decir, cuando ves for_each sabes inmediatamente sin mirar el cuerpo que no hay tal truco.
– bames53
15 de febrero de 2012 a las 19:18
@Klaim: para ser específicos, estoy comparando, por ejemplo std::for_each(v.begin(), v.end(), [](int &i) { ++i; }); con for (auto &i : v) { ++i; }. Acepto que la flexibilidad es de doble filo (goto es muy flexible, ese es el problema). No creo que la restricción de no poder usar break en el for_each versión compensa la verbosidad adicional que exige: los usuarios de for_each Aquí están, en mi opinión, sacrificando la legibilidad y la comodidad reales por una especie de noción teórica de que el for_each es en principio más claro y conceptualmente más simple. En la práctica no es más claro ni más sencillo.
–Steve Jessop
15 de febrero de 2012 a las 19:36
No sé su nombre, pero el código C++03 a menudo usaba la siguiente construcción como reemplazo de la asignación de movimiento faltante:
std::map<Big, Bigger> createBigMap(); // returns by value
void example ()
{
std::map<Big, Bigger> map;
// ... some code using map
createBigMap().swap(map); // cheap swap
}
Esto evitó cualquier copia debido a la elisión de copia combinada con la swap arriba.
En su ejemplo, el intercambio es innecesario, la elisión de copia construiría el valor de retorno en map de todos modos. La técnica que muestras es útil si map ya existe, en lugar de simplemente ser construido. El ejemplo sería mejor sin el comentario “constructor predeterminado barato” y con “// …” entre esa construcción y el intercambio
–Jonathan Wakely
31 de enero de 2014 a las 9:57
Lo cambié según tu sugerencia. Gracias.
– Andrzej
31 de enero de 2014 a las 14:03
El uso de “grande” y “más grande” es confuso. ¿Por qué no explicar cómo importan los tamaños de la clave y el tipo de valor?
– einpoklum
17/06/2016 a las 21:05
¿Ha sido útil esta solución?
Tu feedback nos ayuda a saber si la solución es correcta y está funcionando. De esta manera podemos revisar y corregir el contenido.
Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos.
Configurar y más información
no puedes desaprobar modismos.
– pubis
15 de febrero de 2012 a las 18:33
Charla de Herb Sutter en Going Native 2012 cubrió esto:
– bames53
15 de febrero de 2012 a las 18:35
Ya no se recomienda devolver valores constantes. Obviamente
auto_ptr
también está en desuso.– KerrekSB
15 de febrero de 2012 a las 18:38
Por supuesto que puedes, Pubby. Antes de que se inventaran las plantillas de C++, existía una técnica de macros para crear plantillas. Luego, C ++ los agregó, y la forma anterior se consideró mala.
– Alan Baljeu
15 de febrero de 2012 a las 18:41
Esta pregunta realmente debe trasladarse a Programmers.se.
– Nicolás Bolas
15 de febrero de 2012 a las 19:11