¿Cómo hacer el cambio a C ++ 11?


35

He estado programando en C ++ por un tiempo, pero la mayoría de las cosas se centraron en las características de bajo nivel de C ++. Con eso me refiero principalmente a trabajar con punteros y matrices sin procesar. Creo que este comportamiento se conoce como usar C ++ como C con clases. A pesar de esto, solo había probado C recientemente por primera vez. Me sorprendió gratamente cómo los lenguajes como C # y Java ocultan estos detalles en convenientes clases de biblioteca estándar como Diccionarios y Listas.

Soy consciente de que la biblioteca estándar de C ++ tiene muchos contenedores, como vectores, mapas y cadenas, y C ++ 11 solo se suma a esto al tener std :: array y bucles a distancia.

¿Cómo aprendo mejor el uso de estas características del lenguaje moderno y cuáles son adecuadas para cada momento? ¿Es correcto que la ingeniería de software en C ++ hoy en día esté mayormente libre de administración manual de memoria?

Por último, ¿qué compilador debo usar para aprovechar al máximo el nuevo estándar? Visual Studio tiene excelentes herramientas de depuración, pero incluso VS2012 parece tener una terrible compatibilidad con C ++ 11.


2
Yo diría que llamar "terrible" al soporte C ++ 11 de VS2012 es "un poco exagerado", pero ciertamente podría ser mejor (la falta de listas de inicializadores es especialmente molesta para el código de prueba / juguete). Pero tenga en cuenta que anunciaron que enviarán actualizaciones del compilador independientemente del resto de VS, por lo que creo que podemos esperar algunas características de C ++ 11 en VS2012 en el transcurso de 2013.
Martin Ba,

3
Al principio pensé que sugerirlo para aprender C ++ 11 sería extraño, pero al ver que todavía estás atrapado en la tierra C-With-Classes ... Hace una década leí Koenig / Moo's Accelerated C ++ . En el momento en que ya estaba haciendo metaprogramación de plantillas (solo lo leí para una revisión), pero todavía me pareció una revelación. (Lo utilicé como base para enseñar C ++ desde entonces). Viniendo de C With Classes , el libro puede mostrarle un lenguaje completamente nuevo que no sabía que tenía a su disposición. Son solo 250 páginas, y luego puede avanzar rápidamente a algo específico de C ++ 11, pero IMO es un paso que vale la pena.
sbi

44
g++ -std=c++11
fredoverflow

Respuestas:


50

Primero, algunas reglas generales:

  • Úselo std::unique_ptrcomo un puntero inteligente sin gastos generales. No debería tener que molestarse con punteros crudos con tanta frecuencia. std::shared_ptrTambién es innecesario en la mayoría de los casos. Un deseo de propiedad compartida a menudo revela una falta de pensamiento sobre la propiedad en primer lugar.

  • Úselo std::arraypara matrices de longitud estática y std::vectorpara dinámico.

  • Use algoritmos genéricos ampliamente, en particular:

    • <algorithm>
    • <numeric>
    • <iterator>
    • <functional>
  • Uso autoy decltype()donde sea que beneficien la legibilidad. En particular, cuando se desea declarar una cosa, pero de un tipo que no se preocupan por como un iterador o tipo de plantilla compleja, el uso auto. Cuando desee declarar una cosa en términos del tipo de otra cosa, use decltype().

  • Haga que las cosas sean seguras cuando sea posible. Cuando tienes afirmaciones que imponen invariantes en un tipo particular de cosas, esa lógica se puede centralizar en un tipo. Y esto no necesariamente implica una sobrecarga de tiempo de ejecución. También debería dejar de decir que los moldes de estilo C ( (T)x) deben evitarse en favor de los moldes de estilo C ++ más explícitos (y buscables) (por ejemplo, static_cast).

  • Finalmente, sepa cómo la regla de tres:

    • Incinerador de basuras
    • Copia constructor
    • Operador de asignación

    Se ha convertido en la regla de cinco con la adición del constructor de movimiento y el operador de asignación de movimiento. Y entienda las referencias de valor en general y cómo evitar la copia.

C ++ es un lenguaje complejo, por lo que es difícil de caracterizar mejor manera de utilizar todos de la misma. Pero las prácticas de un buen desarrollo de C ++ no han cambiado fundamentalmente con C ++ 11. Debería preferir los contenedores administrados por memoria en lugar de la administración manual de memoria: los punteros inteligentes facilitan hacer esto de manera eficiente.

Yo diría que el C ++ moderno está en su mayoría libre de administración manual de memoria. La ventaja del modelo de memoria de C ++ es que es determinista , no manual. Las desasignaciones predecibles hacen que el rendimiento sea más predecible.

En cuanto a un compilador, G ++ y Clang son competitivos en términos de características de C ++ 11 y se están poniendo al día rápidamente en sus deficiencias. No uso Visual Studio, así que no puedo hablar a favor ni en contra.

Finalmente, una nota sobre std::for_each: evitarlo en general.

transform, accumulateY erase- remove_ifson buenos edad funcional map, foldy filter. Pero for_eaches más general y, por lo tanto, menos significativo: no expresa ninguna otra intención que no sea bucle. Además de eso, se usa en las mismas situaciones que en el rango for, y es sintácticamente más pesado, incluso cuando se usa sin puntos. Considerar:

for (const auto i : container)
    std::cout << i << '\n';

std::for_each(container.begin(), container.end(), [](int i) {
    std::cout << i << '\n';
});

for (const auto i : container)
    frobnicate(i);

std::for_each(container.begin(), container.end(), frobnicate);

66
¿Existen algunos principios vinculantes para estas reglas generales? Parece una buena lista de sugerencias, pero ... Como un extraño que llega a esta pregunta a través de Google, ¿cómo me ayuda su respuesta a elegir C ++ 11 de una manera basada en principios y usarla sin envolverme alrededor del eje C ++? ?
Robert Harvey

3
+1 para la lista, pero tengo un pequeño problema: cuando (correctamente) advierto en contra std::for_each, hubiera esperado que el rango basado en el bucle sea un mejor reemplazo que el simple for.
Fabio Fracassi

@FabioFracassi: ¡Vaya! Escribí claramente para contrastar std::for_each, no con rango . Lo he eliminado para evitar confusiones.
Jon Purdy

1
Actualizaría si no fuera por std::for_each(). Cuando tienes lambda, sin duda es mejor que un forbucle tradicional . Con un forbucle basado en rango que podría no ser el caso, pero no escribió " forbucle basado en rango ".
sbi

@sbi: En mi opinión, el término " forbucle" incluye " forbucle basado en rango ". He editado con más explicaciones y un ejemplo para aclarar, gracias.
Jon Purdy

12

Como punto de partida:

  • Deje de usar char*para cuerdas. Use std::stringo std::wstringy solo observe cómo su código se acorta, se puede leer más y es más seguro
  • Deje de usar matrices de estilo C (cosas declaradas con [ ]) y use std::vectoro alguna otra clase de contenedor adecuada. Lo bueno de esto std::vectores que conoce su propia longitud, limpia su contenido cuando está fuera de alcance, es fácil de iterar y se hace más grande cuando agrega más elementos. Pero hay otras colecciones que podrían funcionar aún mejor para sus circunstancias.
  • Uso std::unique_ptr- y aprender std::movecasi de inmediato. Dado que esto puede dar lugar a algunos objetos noncopyable, la pereza puede enviarle ocasionalmente hacia std::shared_ptr- y puede que tenga algunos casos de uso reales para std::shared_ptrasí
  • Úselo autocuando declare iteradores y tipos que dependen de declaraciones anteriores (por ejemplo, antes declaró un vector de algo, ahora está declarando algo, use auto)
  • Use algoritmos y for_eachsobre un "raw for" siempre que pueda, ya que evita que otros lean su ciclo cuidadosamente para concluir que de hecho está iterando sobre toda la colección, etc. Si su compilador admite "range for", úselo for_each. Aprender llamadas algoritmo triviales como iota, generate, accumulate, find_ify así sucesivamente.
  • Use lambdas: son la manera fácil de aprovechar los algoritmos. También abren la puerta a mucho más.

No te preocupes demasiado sobre qué compilador usar. La falta "terrible, horrible" de compatibilidad con C ++ 11 en VS2012 es que no hay plantillas variadas (sí, claro, estabas a punto de usar plantillas variadas) y el {}inicializador no está allí. También quiero eso, pero difícilmente dejaré de usar una herramienta de desarrollo útil.

La segunda cosa que hacer, después de abrazar std::, es comenzar a pensar en RAII. Cada vez que tienes

  • acción inicial
  • serie de acciones con algo que obtuviste al iniciar la acción
  • acción de limpieza que debe ocurrir incluso en el caso de excepciones

Entonces, lo que tiene es un constructor, varias funciones miembro y un destructor. Escribe una clase que se encargue de eso por ti. Es posible que ni siquiera tenga que escribir el ctor y el dtor. Poner una shared_ptrvariable como miembro de una clase es un ejemplo de RAII: no se escribe código de administración de memoria, pero cuando su instancia se salga del alcance, sucederán las cosas correctas. Expanda ese pensamiento para cubrir cosas como cerrar archivos, liberar manijas, bloqueos, etc. y el código se volverá más simple y más pequeño (al tiempo que elimina las fugas) ante sus ojos.

Si se siente realmente seguro, purgue printfa favor cout, elimine las macros ( #definecosas) y comience a aprender algunos "modismos avanzados" como PIMPL. Tengo un curso completo sobre esto en Pluralsight que probablemente puedas ver usando su versión de prueba gratuita.


2
Me gusta cómo eres sarcástico acerca de que no use plantillas variadas en el corto plazo, pero creo que falta la inicialización uniforme falta algo realmente importante para la programación diaria.
sbi

No puedo esperar a las listas de inicializadores ... esperando saber cuándo las conseguiremos ...
Kate Gregory

Otra falta importante en VS2012 son las "referencias de valor v3", es decir, el constructor de movimiento generado automáticamente y la asignación de movimiento.
Mr.C64

3

¿Cómo aprendo mejor el uso de estas características del lenguaje moderno y cuáles son adecuadas para cada momento?

Por programación. La experiencia es la mejor manera de aprender.

C ++ 11 tiene muchas características nuevas (auto, rvalue, nuevos punteros inteligentes, solo por nombrar algunos). El mejor comienzo es comenzar a usarlos y leer sobre ellos siempre que pueda y cuando encuentre un artículo interesante.

¿Es correcto que la ingeniería de software en C ++ hoy en día esté mayormente libre de administración manual de memoria?

Eso depende de lo que necesites hacer. La mayoría de las aplicaciones pueden escapar con punteros inteligentes y olvidarse de la administración de memoria. Todavía hay aplicaciones que no pueden escapar tan fácilmente (por ejemplo, si necesitan una ubicación nueva o un asignador de memoria personalizado por cualquier motivo).

Si necesita usar Qt, deberá usar sus reglas para la administración de la memoria.

¿Qué compilador debo usar para aprovechar al máximo el nuevo estándar?

Lo que tenga a la mano que admita el último estándar:

pero ningún compilador admite todas las funciones.


-7

Mi universidad todavía usa C ++ para la enseñanza. He programado con C ++ durante 5 años y ahora soy un estudiante graduado. Por supuesto, ahora estoy usando mucho Java, Ruby, etc. Realmente recomiendo que no se apure demasiado con esas características en un lenguaje como Java. En mi experiencia y opinión, después de las características de bajo nivel de C ++. Debería examinar temas como la programación genérica con C / C ++, como hacer una clase de plantilla, funciones de plantilla, operador sobreescrito, métodos virtuales, punteros inteligentes. Para la Parte de diseño orientado a objetos, hay muchas características que C ++ tiene y Java no, como la herencia múltiple. La herencia es poderosa pero peligrosa también. El nivel de implementación del diseño orientado a objetos en C ++ también es un buen tema. La comunicación entre procesos, los subprocesos, también son importantes en C ++.

Para el compilador y depurador. Sé que Visual Studio es increíble. Pero realmente te recomiendo que aprendas GDB, Valgrind y Make still, y que seas bueno en estas herramientas. Microsoft es increíble, pero hizo muchas cosas por ti. Como estudiante, realmente necesitas aprender esas cosas que Microsoft también hizo contigo. Para el compilador, G ++ es bueno de GNU.

Después de todo, después de tantos años, realmente siento que las cosas más importantes son las características de bajo nivel como la matriz en bruto. Vector es realmente solo una matriz dinámica. Estas son mis recomendaciones, algo quizás demasiado subjetivo, solo toma lo que creas que es correcto.


66
¿Cómo responde esto a la pregunta? La pregunta no se trata de aprender C ++ en general, sino de cambiar a C ++ 11.
Roc Martí
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.