En C, no hay necesidad de lanzar un void *
a ningún otro tipo de puntero, siempre se promociona de forma segura. Sin embargo, en C ++, este no es el caso. P.ej,
int *a = malloc(sizeof(int));
funciona en C, pero no en C ++. (Nota: Sé que no debe usar malloc
en C ++, o para el caso new
, y en su lugar debería preferir los punteros inteligentes y / o el STL; esto se pregunta por pura curiosidad) ¿Por qué el estándar C ++ no permite este lanzamiento implícito, mientras que el estándar C lo hace?
c++
language-features
wolfPack88
fuente
fuente
long *a = malloc(sizeof(int));
¡Vaya, alguien olvidó cambiar solo un tipo!sizeof(*a)
lugar.malloc
no puede devolver un puntero al tipo asignado.new
si C ++ devuelve un puntero al tipo asignado, por lo que el código C ++ escrito correctamente nunca tendrá ningúnvoid *
s para emitir.void
, C no . Cuando se añadió la palabra clave / C idea, que cambiaron para adaptarse a las necesidades del C. Eso fue poco después de que los tipos de puntero comenzaron a ser revisados en absoluto . Vea si puede encontrar el folleto de descripción de K&R C en línea, o una copia antigua de un texto de programación en C como el C Primer de Waite Group . ANSI C estaba lleno, con características respaldadas o inspiradas en C ++, y K&R C era mucho más simple. Por lo tanto, es más correcto que C ++ extendiera C tal como existía en ese momento, y que la C que conoces se eliminó de C ++.Respuestas:
Debido a que las conversiones de tipo implícitas generalmente no son seguras, y C ++ toma una postura más segura para escribir que C hace.
C generalmente permitirá conversiones implícitas, incluso si hay muchas posibilidades de que la conversión sea un error. Esto se debe a que C asume que el programador sabe exactamente lo que está haciendo, y si no, es el problema del programador, no el problema del compilador.
C ++ generalmente no permitirá cosas que podrían ser errores, y requerirá que explique explícitamente su intención con un tipo de conversión. Eso es porque C ++ está tratando de ser amigable con los programadores.
Puede preguntar por qué es amigable cuando en realidad requiere que escriba más.
Bueno, ya ves, cualquier línea de código dada, en cualquier programa, en cualquier lenguaje de programación, generalmente se leerá muchas más veces de lo que se escribirá (*). Entonces, la facilidad de lectura es mucho más importante que la facilidad de escritura. Y al leer, tener conversiones potencialmente inseguras se destacan por medio de conversiones de tipo explícito ayuda a comprender lo que está sucediendo y a tener un cierto nivel de certeza de que lo que está sucediendo es, de hecho, lo que estaba destinado a suceder.
Además, el inconveniente de tener que escribir el reparto explícito es trivial en comparación con el inconveniente de horas y horas de resolución de problemas para encontrar un error causado por una asignación errónea sobre la que podría haber sido advertido, pero nunca lo fue.
(*) Idealmente, se escribirá solo una vez, pero se leerá cada vez que alguien necesite revisarlo para determinar su idoneidad para la reutilización, y cada vez que haya una solución de problemas, y cada vez que alguien necesite agregar código cerca de él, y luego cada vez que hay una solución de problemas del código cercano, y así sucesivamente. Esto es cierto en todos los casos, excepto en los scripts de "escribir una vez, ejecutar y luego tirar", por lo que no es de extrañar que la mayoría de los lenguajes de scripting tengan una sintaxis que facilite la escritura sin tener en cuenta la facilidad de lectura. ¿Alguna vez pensaste que Perl es completamente incomprensible? No estas solo. Piense en tales idiomas como idiomas de "solo escritura".
fuente
void*
son más inseguras en C ++, porque con la forma en que se implementan ciertas características de OOP en C ++, el puntero al mismo objeto puede tener un valor diferente según el tipo de puntero.Esto es lo que dice Stroustrup :
Luego muestra un ejemplo de cómo el vacío * puede ser peligroso y dice:
Finalmente, él nota:
Él entra en muchos más detalles sobre esto en The Design and Evolution of C ++ .
Por lo tanto, la respuesta se reduce a: El diseñador de lenguaje cree que es un patrón inseguro, por lo que lo hizo ilegal y proporcionó formas alternativas de lograr para qué se usaba normalmente el patrón.
fuente
malloc
ejemplo, vale la pena señalar quemalloc
(obviamente) no llamará a un constructor, por lo que si es un tipo de clase para el que está asignando memoria, ser capaz de emitir implícitamente al tipo de clase sería engañoso.Siempre se promociona, sí, pero apenas con seguridad .
C ++ deshabilita este comportamiento precisamente porque intenta tener un sistema de tipos más seguro que C, y este comportamiento no es seguro.
Considere en general estos 3 enfoques para la conversión de tipos:
Bueno, 1 es feo y un obstáculo práctico para hacer cualquier cosa, pero realmente podría usarse donde se necesita mucho cuidado. C optó por 2, que es más fácil de implementar, y C ++ por 3, que es más difícil de implementar pero más seguro.
fuente
Por definición, un puntero vacío puede apuntar a cualquier cosa. Cualquier puntero se puede convertir en un puntero vacío y, por lo tanto, podrá volver a convertirlo llegando exactamente al mismo valor. Sin embargo, los punteros a otros tipos pueden tener restricciones, como restricciones de alineación. Por ejemplo, imagine una arquitectura donde los caracteres pueden ocupar cualquier dirección de memoria pero los números enteros deben comenzar incluso en los límites de la dirección. En ciertas arquitecturas, los punteros enteros incluso pueden contar 16, 32 o 64 bits a la vez, de modo que un char * podría tener un múltiplo del valor numérico de int * mientras apunta al mismo lugar en la memoria. En este caso, la conversión de un vacío * en realidad redondea los bits que no se pueden recuperar y, por lo tanto, no son reversibles.
En pocas palabras, el puntero vacío puede apuntar a cualquier cosa, incluidas las cosas que otros punteros pueden no ser capaces de señalar. Por lo tanto, la conversión al puntero vacío es segura pero no al revés.
fuente