Con la nueva norma, hay nuevas formas de hacer las cosas, y muchos son más bonitas que las de las viejas formas, pero la forma antigua es todavía bien. También es claro que la nueva norma no oficialmente denigran mucho, por razones de compatibilidad con versiones anteriores. Así que la pregunta que queda es:

Lo que las viejas formas de la codificación son sin duda inferior a la de C++11 estilos, y ¿qué podemos hacer ahora en su lugar?

De responder a esta pregunta, puede omitir el paso de las cosas obvias, como «el uso de automóviles variables».

  • No se puede menospreciar los modismos.
  • Herb Sutter hablar en Ir Nativo de 2012, cubrió este:
  • Volviendo constante de valores no es más animado. Obviamente auto_ptr está en desuso, también.
  • Por supuesto, usted puede, Pubby. Antes de las plantillas de C++, se han inventado, no fue una macro técnica para hacer plantillas. Luego C++ agregado, y de la manera antigua era considerado malo.
  • const_ptr, make_shared (y la make_unique que debería haber sido en el estándar), y r-value de referencia cambiado la forma «correcta» de hacer las cosas de una manera grande.
  • nuevas características de lenguaje se han añadido para hacer algunas de las cosas más fácil, por supuesto que ustedes son libres de ignorarlos y seguir haciendo las cosas de la manera difícil.
  • Esta pregunta realmente necesita ser movido para los Programadores.se.
  • En eso tienes al revés: la macro técnica para hacer las plantillas se consideraba malo, por lo que las plantillas de C++ se inventaron.
  • Me gustaría considerar la posibilidad de 1/4 de Efectivo C++ como malo. Es la mejor manera en la actual C++, pero sólo puedo desear una manera más fácil estaban disponibles.
  • ¿por qué regresar const de valores no es más animados en C++11?
  • Se rompe mover la semántica.
  • Cómo se rompe mover la semántica?
  • Un const valor no puede ser modificado, y por lo tanto no se deben mover.

InformationsquelleAutor Alan Baljeu | 2012-02-15

9 Comentarios

  1. 171
    1. Final De La Clase: C++11 proporciona el final especificador para evitar la derivación de clases
    2. C++11 de lambdas reducir sustancialmente la necesidad de la función con nombre de objeto (functor) clases.
    3. Mover Constructor: Las formas mágicas en las que std::auto_ptr obras no son necesarios debido a soporte de primera clase para r-value referencias.
    4. Seguro bool: Esto fue mencionado anteriormente. Explícito de los operadores de C++11 obviar esta muy comunes en C++03 idioma.
    5. Shrink-a-fit: Muchos de C++11 contenedores STL proporcionar un shrink_to_fit() función miembro, que debe eliminar la necesidad de intercambio con un temporal.
    6. Temporal De La Clase Base: Algunas viejas bibliotecas de C++ el uso de este complejo idioma. Con mover la semántica ya no es necesario.
    7. Seguro Del Tipo Enum Las enumeraciones son muy seguros en C++11.
    8. Prohibición de la asignación del montón: El = delete sintaxis es una manera mucho más directa de decir que una funcionalidad particular es explícitamente rechazada. Esto es aplicable a la prevención de la asignación del montón (es decir, =delete para que los estados operator new), la prevención de copias, cesión, etc.
    9. Plantilla typedef: Alias plantillas en C++11 de reducir la necesidad de simple plantilla typedefs. Sin embargo, los complejos de tipo de generadores todavía necesita meta funciones.
    10. Algunos numérica en tiempo de compilación cálculos, tales como Fibonacci puede ser fácilmente reemplazado con constante generalizada expresiones
    11. result_of: Los usos de la plantilla de clase result_of debe ser reemplazado con decltype. Creo que result_of utiliza decltype cuando está disponible.
    12. En-miembro de la clase inicializadores salvar a escribir para la inicialización predeterminada de los miembros no estáticos con los valores predeterminados.
    13. En el nuevo C++11 código NULL debe ser redefinido como nullptr, pero ver STL a hablar para saber por qué se decidió en contra de ello.
    14. La expresión de la plantilla fanáticos están encantados de tener la trailing tipo de devolución sintaxis de la función en C++11. No más de 30 líneas de retorno tipos!

    Creo que voy a parar allí!

    • Gracias por la detallada cosas!
    • Gran respuesta, pero me gustaría huelga result_of de la lista. A pesar de la engorroso typename antes, creo que 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 de ambos trabajan para SFINAE (que solía ser una ventaja de decltype que result_of no ofrecen)
    • Final no es una palabra clave. en.cppreference.com/w/cpp/language/final
    • Respecto a la 14) todavía estoy llorando que tengo uso de macros para escribir el mismo código dos veces: una vez para el cuerpo de la función y de una vez por el decltype() declaración de…
    • Me gustaría señalar que este tema está vinculado desde esta página de Microsoft como un «Para más información», artículo en una introducción general a la del lenguaje C++, pero este tema es un altamente especializado! Sugiero que una breve «Este tema NO es para C++ principiantes!» asesoramiento ser incluidas al principio del tema o esta respuesta?
    • Re 12: «En-miembro de la clase de inicialización» – que el nuevo lenguaje no es un lenguaje obsoleto, ¿no? Cambiar el orden de la frase tal vez? Re 2: Functors son muy útiles cuando se desea pasar de todo tipos en lugar de los objetos (especialmente en los parámetros de la plantilla). Por lo que sólo se algunos usos de functors que están en desuso.
    • Volver a en-miembro de la clase de inicialización: En C++17, puede inicializar incluso la estática de los miembros en la definición de la clase.

  2. 65

    A un punto en el tiempo se sostuvo que uno debería volver const valor en lugar de simplemente por valor:

    const A foo();
    ^^^^^

    Este fue en su mayoría inofensivas en C++98/03, y puede que incluso han cogido un par de bugs que parecía:

    foo() = a;

    Pero volviendo por const está contraindicado en C++11, ya que inhibe mover semántica:

    A a = foo();  //foo will copy into a instead of move into it

    Tan sólo relajarse y código:

    A foo();  //return by non-const value
    • Los errores evitables, no obstante, puede ahora ser capturados mediante el uso de la referencia de clasificación de funciones. Como en el caso anterior, la definición de A& operator=(A o)& en lugar de A& operator=(A o). Estos prevenir los errores tontos y que las clases se comportan más como los tipos básicos y no impiden mover la semántica.
  3. 61

    Tan pronto como usted puede abandonar 0 y NULL en favor de nullptr, hacerlo!

    De código no genérico el uso de 0 o NULL no es un problema tan grande. Pero tan pronto como usted comience a pasar alrededor de puntero nulo constantes en el código genérico la situación cambia rápidamente. Cuando se pasa 0 a un template<class T> func(T) T se presenta deducida como un int y no como un puntero nulo constante. Y no puede ser convertida de nuevo a un puntero nulo constante después de eso. Esta cascada en un atolladero de problemas que simplemente no existen si el universo sólo nullptr.

    C++11 no van a dejar de usar 0 y NULL como puntero nulo constantes. Pero usted debe codificar como si lo hizo.

    • ¿qué es decltype(nullptr)?
    • Es std::nullptr_t.
    • Sugieren que este ser reformulado como el lenguaje obsoleto en lugar de la nueva convención a adoptar (por ejemplo, «El uso de 0 o NULL punteros null»).
  4. 24

    Una de las cosas que acaba de hacer usted para evitar que la escritura de algoritmos básicos en C++11, es la disponibilidad de las lambdas en combinación con los algoritmos proporcionados por la biblioteca estándar.

    Estoy usando los de ahora y es increíble cómo a menudo que acaba de decirle lo que usted quiere hacer mediante el uso de count_if(), for_each() u otros algoritmos en lugar de tener que escribir la maldita bucles de nuevo.

    Una vez que usted está usando un compilador de C++11 con un completo C++11 de la biblioteca estándar, usted no tiene ninguna buena excusa más para no usar algoritmos estándar para construir su. Lambda acaba de matar.

    ¿Por qué?

    En la práctica (después de haber utilizado esta forma de escritura de algoritmos de mí mismo) que se siente mucho más fácil de leer algo que se construye con sencillas palabras el significado de lo que se hace que con algunos bucles que usted tiene que uncrypt saber el significado. Que dijo, haciendo lambda argumentos automáticamente deducido ayudaría mucho a que la sintaxis del código más fácilmente comparable a una prima de bucle.

    Básicamente, algoritmos de lectura hecha con algoritmos estándar son mucho más fáciles de palabras como ocultar los detalles de implementación de los bucles.

    Supongo que sólo nivel superior algoritmos tienen que ser pensado ahora que tenemos un nivel inferior algoritmos para construir.

    • En realidad hay una buena excusa. Estás usando Boost.La gama de algoritmos, que son mucho mejor 😉
    • Jaja sí, obviamente, en el caso de la biblioteca estándar, puede utilizar rangos sería aún mejor.
    • No veo que for_each con una lambda es mejor que la gama equivalente basado en bucle, con el contenido de la lambda en el bucle. El código es más o menos el mismo, pero la lambda introduce algo más de puntuación. Usted puede utilizar equivalentes de cosas como boost::irange para aplicarlo a más de bucles que sólo aquellos que, obviamente, el uso de iteradores. Además de la gama basada en bucle for tiene una mayor flexibilidad, en la que puedes salir temprano si es necesario (por return o por break), mientras que con for_each tendría que tirar.
    • Dicho esto, hay mucho menos de los algoritmos disponibles que en el estándar actual de la biblioteca.
    • Se han explicado por mucho mejor que la gente de mí antes, pero, básicamente, un bucle es un bucle, mientras que un for_each es «un bucle que recorre todos los elementos de un «rango»». En la práctica (después de haber utilizado esta forma de escritura de algoritmos de mí mismo) que se siente mucho más fácil de leer algo que se construye con sencillas palabras el significado de lo que se hace que con algunos bucles que usted tiene que uncrypt saber el significado. Que dijo, haciendo lambda argumentos automáticamente deducido ayudaría mucho a que la sintaxis del código más fácilmente comparable a una prima de bucle, por lo que entiendo tu sentimiento.
    • Aún así, la disponibilidad de la gama basada en for hace que el habitual it = c.begin(), const end = c.end(); it != end; ++it lenguaje desaparecido.
    • Él está hablando específicamente sobre la for_each algoritmo. Es equivalente a la gama basado en la sintaxis de C++11. Y señala cuánto es mejor que eso, ya que puede continue, break, return, y las cosas que no puede con lambdas. El rango para no es un «bucle»; se trata específicamente de un lazo sobre todos los elementos de una serie.
    • Por supuesto que hay menos de los algoritmos. El punto de Boost.Rango de algoritmos es que se puede combinar de ellos. Por el emparejamiento de comenzar y terminar los iteradores, puede en cadena de la gama de algoritmos. Así que cosas como «count_if» son innecesarios en el Impulso.Rango; usted sólo tiene que utilizar un algoritmo de filtrado, y la tubería de salida en un algoritmo de conteo.
    • Una de las ventajas de la for_each algoritmo en el rango basado en bucle for es que no break o return. Es decir, cuando vea for_each saber inmediatamente, sin mirar el cuerpo que no existe tal problema.
    • cierto, pero si usted está preocupado por ella, entonces (a) el cuerpo del bucle es demasiado largo para su gusto «de un vistazo» código de lectura de estilo, y (b) probablemente también preocupado de que podría lanzar. No creo que podamos esperar mucho en C++ (o cualquier otro idioma con excepciones) a lo largo de esas líneas, aunque la gente que escribe herramientas de análisis de código podría ser capaz de decirme que las excepciones son en cierta manera importante más manejable que break. Por suerte para mí, que he coloreado de sintaxis, por lo que puedo identificar fácilmente los principios de bucle termina.
    • para ser más específicos, la 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, que es el problema). No creo que la restricción de no poder utilizar break en el for_each versión compensa por el nivel de detalle que exige — los usuarios de for_each aquí son de la OMI sacrificar real legibilidad y comodidad para un tipo de noción teórica de que el for_each es en principio más clara y conceptualmente más simple. En la práctica no es más clara o más simples.
    • Obviamente hay que optar entre los dos. Una muy breve y simple cuerpo del bucle significa que el lambda de la sintaxis y los iteradores se utiliza en for_each es relativamente pesado, pero no creo que los cambios siempre van a salir en favor de amplia base para. Aunque para ser justos yo soy una de esas personas que utiliza algoritmos con bind1st, bind2nd, y el estándar de functors antes de que tuviéramos lambda y se unen, así que lo que me parece más legible no es necesariamente la misma que la de los demás a encontrar legible (por ejemplo, un bucle que se incrementa cada elemento en un array creo transform en lugar de for_each).
    • Pequeñeces: it = c.begin(), const end = c.end(); no es válido, const se aplica a todas las declaraciones.
    • for_each nunca ha tenido mucho amor. Antes de C++11, su utilidad se reduce al tener que escribir un no-local de la función. Las Lambdas salvó el día, pero llegó el rango de declaraciones y lo golpeó fuera del parque. Lo siento por for_each.
    • para resolver el «no break o return» asunto: para (auto &i : v) {func();}. Ahora usted sabe que func() no se puede romper o la devolución de tu bucle, con la ventaja añadida de que no tenía necesidad de recurrir a for_each o lambdas.
    • Esta derrota el propósito de la localidad de código iniciado por tanto lambda y para cada uno de los bucles.

  5. 10

    Deberá implementar versiones personalizadas de swap con menos frecuencia. En C++03, eficiente no tirar swap a menudo es necesario para evitar el costoso y tirar copias, y desde std::swap utiliza dos copias, swap a menudo tiene que ser personalizado. En C++, std::swap utiliza move, y así el foco de atención se centra en la implementación eficiente y no tirar mover los constructores y mover operadores de asignación. Ya que para estos el valor predeterminado es a menudo bien, esto será mucho menos trabajo que en C++03.

    Generalmente es difícil predecir qué expresiones idiomáticas utilizadas, ya que son creados a través de la experiencia. Podemos esperar una «Eficaz C++11» tal vez el próximo año, y una «C++11 Estándares de Codificación» sólo en tres años, porque la experiencia necesaria no está allí todavía.

    • Estoy dudoso de este. Se recomienda estilo es el uso de swap para mover y copiar la construcción, pero no std::swap porque eso sería circular.
    • Sí, pero el movimiento constructor por lo general requiere una costumbre de intercambio, o es esencialmente equivalente.
  6. 2

    No sé el nombre, pero C++03 código a menudo se utiliza la siguiente construcción como un reemplazo para la falta mover asignación:

    std::map<Big, Bigger> createBigMap(); //returns by value
    
    void example ()
    {
      std::map<Big, Bigger> map;
    
      //... some code using map
    
      createBigMap().swap(map);  //cheap swap
    }

    Este evitarse cualquier copia debido a copiar elisión combinado con el swap arriba.

    • En su ejemplo, el swap es innecesario, copia elisión construiría el valor de retorno en map de todos modos. La técnica que muestran es útil si map ya existe, en lugar de ser construido. El ejemplo sería mejor sin el «barato constructor predeterminado» comentario y con «// …» entre la construcción y el intercambio
    • He cambiado como por su sugerencia. Gracias.
    • El uso de «grande» y «más Grande» es confuso. Por qué no explicar cómo el tamaño de la clave y el tipo de valor de la materia?
  7. 1

    Cuando me di cuenta de que un compilador utilizando el estándar C++11 ya no faltas el siguiente código:

    std::vector<std::vector<int>> a;

    para que supuestamente contienen operador>>, empecé a bailar. En las versiones anteriores habría que hacer

    std::vector<std::vector<int> > a;

    Para empeorar las cosas, si alguna vez ha tenido para la depuración de esto, usted sabe lo terrible son los mensajes de error que salen de esta.

    Yo, sin embargo, no sé si esto es «obvia» para usted.

    • Esta característica se añadió ya en la anterior C++. O, al menos, Visual C++ implementado de acuerdo con las normas de discusión, muchos años antes.
    • Por supuesto, hay muchos que no lo está siendo añadido compilador/bibliotecas. Había toneladas de compiladores que había «auto» declaración de variable antes de C++11, pero no se podía estar seguro de que su código puede ser en realidad compilado por cualquier otra cosa. La pregunta era acerca de la norma, no se trata de «estaba allí cualquier compilador que podría hacer esto».
  8. 1

    Retorno por valor ya no es un problema. Con mover la semántica y/o valor de retorno de la optimización (depende del compilador) la codificación de las funciones más natural, sin la sobrecarga o el costo (la mayoría del tiempo).

    • … pero que modismo ha quedado obsoleta?
    • No es un modismo, pero fue una buena práctica ya no es necesario. Incluso con el compilador compatible RVO que es opcional. en.wikipedia.org/wiki/Return_value_optimization «En las primeras etapas de la evolución de C++, el lenguaje de la imposibilidad de manera eficiente devolver un objeto de tipo de clase de una función se considera una debilidad…..» struct Datos { char bytes[16]; }; void f(Datos *p) { // genera como resultado directo *p } int main() { Datos d; f(&d); }
    • Yo estaba insinuando usted debe frase de su respuesta como «la costumbre de evitar el retorno por valor no es relevante como etc. etc. etc.»

Dejar respuesta

Please enter your comment!
Please enter your name here