Actualmente me estoy enseñando C ++. Soy muy competente en C #, y me preguntaba qué prácticas comunes de C # pueden llevar a dificultades en C ++, y qué debería hacer un programador de C ++ en su lugar.
Actualmente me estoy enseñando C ++. Soy muy competente en C #, y me preguntaba qué prácticas comunes de C # pueden llevar a dificultades en C ++, y qué debería hacer un programador de C ++ en su lugar.
Lo primero y más importante, debe aprender RAII: La adquisición de recursos es la inicialización
Asegúrate de usar new
, entonces no olvides usar delete
en tu programa. No mezcle new
con malloc
, y delete
con free
. new
y malloc
no son intercambiables, ni son delete
y free
. Como en C #, usted no escribe destructor (generalmente), así que en C ++ necesita específicamente aprender a usar destructor de manera efectiva para liberar memoria y otros recursos. Una vez que conozca estos conceptos, intente diseñar cosas en RAII-way para manejar los recursos de manera efectiva, de modo que no tenga que tratar con new
y delete
explícitamente en su código en todas partes.
Debe aprender qué es puntos de secuencia , comportamiento indefinido , comportamiento no especificado , comportamiento definido por la implementación en C ++. Como C # no tiene estos conceptos, eso significa que nunca escuchó estos términos mientras programaba en C #, por lo que es muy probable que escriba código en C ++ (como a[++i]= i
, i+=++i
) cuyo comportamiento es no bien definido. Por eso te recomiendo que leas estos temas:
PD: Ya que hablé sobre la memoria nueva, eliminada, sin formato, etc., permítame agregar una diferencia interesante entre C ++ y C #:
En C ++, this
es un puntero, mientras que en C # this
es una referencia!
El más fundamental, por supuesto, está relacionado con la falta de un recolector de basura:
no use
new
más de lo necesario. Comprenda el lenguaje RAII : asigne sus objetos en la pila (sin usarnew
) y deje que sus destructores se encarguen de limpiado la memoria asignada para usted. O use punteros inteligentes para manejar algo de esto por usted.
Aparte de eso, diría que hay algunos problemas de estilo a los que debes acostumbrarte. C # sigue siendo, a pesar de su coqueteo con la programación funcional, un lenguaje OOP.
C ++ es un lenguaje de paradigma múltiple, y en C ++ moderno, OOP simplemente no juega un papel muy importante. Sin embargo, definitivamente deberías considerar la programación genérica. Comprender cómo usar el STL (las estructuras de datos, los iteradores y los algoritmos en la biblioteca estándar). Y te sientes un poco sucio cuando escribes una función virtual.
La administración automática de memoria y la recolección de basura es probablemente algo que podría faltar en C ++. Pero en mi humilde opinión, lo que más extrañará es la consistencia del marco .NET en el que ha dado muchas cosas por sentado simplemente porque están incorporadas en el BCL.
El mayor problema que he visto es la tendencia a nuevos objetos por todas partes y usarlos en el montón. Claro, es posible que tengan mucho cuidado al eliminarlos ya que no hay GC, pero el problema es la asignación en el montón en primer lugar. C ++ funciona mejor poniendo cosas en la pila y copiándolas. Si aún necesita un solo objeto compartido, use shared_ptr para contenerlo.
Eso sí, esto no es exclusivo de los desarrolladores de C #, he visto que unos pocos desarrolladores web hacen lo mismo.
La recolección de basura es grande, pero si usa punteros inteligentes, puede evitar la mayoría de los problemas con eso.
Un problema más generalizado es el de la seguridad de excepción. Esto no es tanto un hábito de C # que te meterá en problemas, sino la falta de uno. En C #, obtiene seguridad con using
blocks y finally
handlers. C ++ no tiene ninguno. Lo que tienes es una técnica llamada RAII (la adquisición de recursos es la inicialización), donde las clases están cuidadosamente diseñadas para que sus destructores limpien las cosas. Entonces, en lugar de usar un bloque using
para abrir un archivo, stack-allocate el objeto del archivo y el destructor se vaciará y cerrará el archivo. Es importante diseñar y usar las clases de esta manera, pero una vez que adquiera el hábito, su código puede ser bastante seguro. Es solo un enfoque diferente. En general, el hecho de que C ++ tenga una asignación de objetos de pila requerirá algún ajuste.
RAII es definitivamente uno de los aspectos clave de C ++ para aprender. Otros carteles lo han descrito, pero agregaré que es bastante similar a IDisposable de C # interfaz combinada con la utilizando la palabra clave .
Tenga cuidado con los tipos char
y string
en C ++, han crecido a partir de muchos años de experiencia (amarga) y existen diferentes tipos. En C # todos son Unicode (olvido la codificación), pero en C ++ un char
suele depender de la página de códigos del sistema. Por ejemplo, US-English Windows usa una página de códigos de Windows 1252 de manera predeterminada para los programas que no son Unicode. Las páginas de códigos son difíciles de administrar y son propensas a errores, así que use wchar_t
y el STL's std::wstring
. También tenga en cuenta que el tamaño de char
y wchar_t
es diferente entre los diferentes compiladores. Muchos compiladores de C ++ basados en Linux utilizan un tamaño de carácter diferente y el consejo es diferente de nuevo. Consulte enlace para obtener más información info.
Tenga en cuenta el alcance de las variables y cuándo se destruirán. En general, es una mala práctica hacer return new object()
, ya que la persona que llama no se da cuenta de que necesita limpiar el valor de retorno.
Evite el uso de punteros desnudos, en su lugar use unique_ptr o shared_ptr
+ Use make_shared < > () para crear un shared_ptr. Desafortunadamente, no hay unique_ptr
equivalente en este momento.
Obtenga información sobre move semantics : pueden ayudar Lote con RAII. No tengo conocimiento de un equivalente en C #
Comprenda qué es un puntero opaco . Si está utilizando la API de Windows, encontrará muchos de estos en forma de HANDLE
s.
Tenga cuidado al almacenar listas (por ejemplo, std::vector
o std::deque
) de los objetos que pueden heredarse, ya que esto puede llevar a corte donde la parte heredada de la clase se corta para que solo quede el tipo declarado.
Olvídate de intentar- (catch-) finalmente y acostúmbrate a realizar la asignación / desasignación de recursos a través de constructores / destructores (RAII).
Evita la programación en C ++ como si fuera C #, esa es la práctica que debes evitar. En realidad, aprende el idioma, sus peculiaridades, las partes buenas y sus expresiones idiomáticas.
Lo más obvio probablemente sería dar por sentado la recolección de basura. Los objetos sin referencia deben eliminarse manualmente en C ++, pero en C # tienes el GC para cuidarlos.
Administración de memoria, aprobación de convenciones y punteros, aunque si utiliza una biblioteca como Boost, es probable que sea un problema menor. Sin embargo, si te estás enseñando a ti mismo en C ++, probablemente sea una buena idea no usar ninguna biblioteca y aprender lo básico primero.
Administración de memoria, vigilando las fugas de memoria y acostumbrándose a no tener recolección automática de basura.