Con el nuevo estándar, hay nuevas formas de hacer las cosas, y muchas son más agradables que las viejas, pero la vieja forma todavía está bien. También está claro que el nuevo estándar no se desprecia oficialmente mucho, por razones de compatibilidad con versiones anteriores. Entonces la pregunta que queda es:
¿Qué formas antiguas 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".
auto_ptr
, también está en desuso.Respuestas:
final
especificador para evitar la derivación de clasestd::auto_ptr
obras ya no son necesarias debido al soporte de primera clase para las referencias de valor.shrink_to_fit()
función miembro, que debería eliminar la necesidad de intercambiar por una temporal.= delete
sintaxis es una forma mucho más directa de decir que una funcionalidad particular se niega explícitamente. Esto es aplicable para evitar la asignación del montón (es decir,=delete
para el miembrooperator new
), evitar copias, asignación, etc.result_of
: Los usos de la plantilla de claseresult_of
deben reemplazarse pordecltype
. Creo queresult_of
usadecltype
cuando está disponible.NULL
debe redefinirse comonullptr
, pero vea la charla de STL para saber por qué decidieron no hacerlo.¡Creo que me detendré allí!
fuente
result_of
de la lista. A pesar de lo engorroso que setypename
necesitaba antes, creo que atypename result_of<F(Args...)::type
veces puede ser más fácil de leer quedecltype(std::declval<F>()(std::declval<Args>()...)
, y con la aceptación de N3436 en el documento de trabajo, ambos trabajan para SFINAE (que solía ser una ventaja de lodecltype
queresult_of
no ofrecía)En un momento dado se argumentó que uno debería regresar por
const
valor en lugar de solo por valor:Esto fue mayormente inofensivo en C ++ 98/03, e incluso puede haber detectado algunos errores que parecían:
Pero regresar
const
está contraindicado en C ++ 11 porque inhibe la semántica del movimiento:Así que relájate y codifica:
fuente
A& operator=(A o)&
lugar deA& operator=(A o)
. Estos evitan los errores tontos y hacen que las clases se comporten más como los tipos básicos y no evitan la semántica de movimiento.¡Tan pronto como pueda abandonar
0
yNULL
en favornullptr
, hágalo!En el código no genérico, el uso de
0
oNULL
no es tan importante. Pero tan pronto como comience a pasar constantes de puntero nulo en código genérico, la situación cambia rápidamente. Cuando pasa0
a untemplate<class T> func(T)
T
se deduce como unint
y no como un puntero nulo constante. Y no se puede convertir de nuevo a un puntero nulo constante después de eso. Esto cae en un atolladero de problemas que simplemente no existen si el universo solo se usanullptr
.C ++ 11 no se desprecia
0
yNULL
como constantes de puntero nulo. Pero debe codificar como si lo hiciera.fuente
std::nullptr_t
.0
oNULL
para punteros nulos").Safe bool idiom →
explicit operator bool()
.Constructores de copia privada (boost :: noncopyable) →
X(const X&) = delete
Simulando la clase final con destructor privado y herencia virtual →
class X final
fuente
Una de las cosas que simplemente hace que evite 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 dices lo que quieres hacer usando count_if (), for_each () u otros algoritmos en lugar de tener que volver a escribir los malditos bucles.
Una vez que está utilizando un compilador de C ++ 11 con una biblioteca estándar completa de C ++ 11, ya no tiene una buena excusa para no usar algoritmos estándar para construir su propio . Lambda acaba de matarlo.
¿Por qué?
En la práctica (después de haber utilizado esta forma de escribir algoritmos yo mismo), es mucho más fácil leer algo que está construido con palabras sencillas que significan lo que se hace que con algunos bucles que hay que descifrar para saber el significado. Dicho esto, hacer que los argumentos lambda se deduzcan automáticamente ayudaría mucho a que la sintaxis sea más fácilmente comparable a un bucle sin formato.
Básicamente, los algoritmos de lectura hechos con algoritmos estándar son mucho más fáciles ya que las palabras ocultan los detalles de implementación de los bucles.
Supongo que solo debemos pensar en algoritmos de nivel superior ahora que tenemos algoritmos de nivel inferior para construir.
fuente
for_each
con un lambda sea mejor que el bucle for basado en rango equivalente, con el contenido del lambda en el bucle. El código se ve más o menos igual, pero la lambda introduce algunos signos de puntuación adicionales. Puede usar equivalentes de cosas comoboost::irange
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 temprano si es necesario (porreturn
o porbreak
), mientras que con lafor_each
necesidad de lanzar.for
hace que elit = c.begin(), const end = c.end(); it != end; ++it
idioma habitual desaparezca.for_each
algoritmo sobre el rango basado en el bucle es que no puedebreak
o noreturn
. Es decir, cuando vesfor_each
que sabes de inmediato sin mirar el cuerpo que no hay tal engaño.std::for_each(v.begin(), v.end(), [](int &i) { ++i; });
confor (auto &i : v) { ++i; }
. Acepto que la flexibilidad es de doble filo (goto
es muy flexible, ese es el problema). No creo que la limitación de no poder utilizarbreak
en losfor_each
compensa de versión para el nivel de detalle adicional que exige - usuarios defor_each
aquí están sacrificando la OMI lectura real y conveniencia con una especie de noción teórica de que elfor_each
es , en principio, más clara y conceptualmente más simple En la práctica no es más claro ni más simple.Deberá implementar versiones personalizadas con
swap
menos frecuencia. En C ++ 03, aswap
menudo es necesario un no-lanzamiento eficiente para evitar costosas y tirar copias, y dado questd::swap
usa dos copias, aswap
menudo tiene que ser personalizado. En C ++,std::swap
utilizamove
, y por lo tanto, el enfoque cambia en la implementación de constructores de movimientos y operadores de asignación de movimientos eficientes y no arrojables. Dado que para estos el valor predeterminado es a menudo correcto, será mucho menos trabajo que en C ++ 03.En general, es difícil predecir qué expresiones idiomáticas se utilizará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 "Estándares de codificación C ++ 11" solo en tres años porque la experiencia necesaria aún no existe.
fuente
No sé el nombre, pero el código C ++ 03 a menudo usaba la siguiente construcción como reemplazo de la asignación de movimiento faltante:
Esto evitó cualquier copia debido a la elisión de copia combinada con lo
swap
anterior.fuente
map
todos modos. La técnica que muestra es útil simap
ya existe, en lugar de simplemente ser construida. El ejemplo sería mejor sin el comentario de "constructor predeterminado barato" y con "// ..." entre esa construcción y el intercambioCuando noté que un compilador que usa el estándar C ++ 11 ya no falla el siguiente código:
por supuestamente contener operador >>, comencé a bailar. En las versiones anteriores habría que hacer
Para empeorar las cosas, si alguna vez tuvo que depurar esto, ya sabe lo horrendos que son los mensajes de error que salen de esto.
Yo, sin embargo, no sé si esto fue "obvio" para usted.
fuente
El retorno por valor ya no es un problema. Con la semántica de movimiento y / o la optimización del valor de retorno (dependiente del compilador), las funciones de codificación son más naturales sin gastos generales o costos (la mayoría de las veces).
fuente