¿Alguien puede explicar por qué los punteros no se inicializan en NULL
?
Ejemplo:
void test(){
char *buf;
if (!buf)
// whatever
}
El programa no entraría en el if porque buf
no es nulo.
Me gustaría saber por qué, en qué caso necesitamos una variable con basura activada, especialmente punteros que se dirijan a la basura en la memoria.
c++
memory
pointers
initialization
Jonathan
fuente
fuente
Respuestas:
Todos sabemos que el puntero (y otros tipos de POD) deben inicializarse.
La pregunta entonces es 'quién debería inicializarlos'.
Bueno, básicamente hay dos métodos:
Supongamos que el compilador inicializó cualquier variable no inicializada explícitamente por el desarrollador. Luego nos encontramos con situaciones en las que inicializar la variable no era trivial y la razón por la que el desarrollador no lo hizo en el punto de declaración fue que necesitaba realizar alguna operación y luego asignar.
Entonces ahora tenemos la situación en la que el compilador ha agregado una instrucción adicional al código que inicializa la variable a NULL y luego se agrega el código del desarrollador para realizar la inicialización correcta. O bajo otras condiciones, la variable potencialmente nunca se usa. Muchos desarrolladores de C ++ gritarían mal en ambas condiciones a costa de esa instrucción adicional.
No es solo cuestión de tiempo. Pero también espacio. Hay muchos entornos en los que ambos recursos son un bien escaso y los desarrolladores tampoco quieren renunciar.
PERO : Puede simular el efecto de forzar la inicialización. La mayoría de los compiladores le advertirán sobre las variables no inicializadas. Así que siempre cambio mi nivel de advertencia al nivel más alto posible. Luego dígale al compilador que trate todas las advertencias como errores. En estas condiciones, la mayoría de los compiladores generarán un error para las variables que no están inicializadas pero que se usan y, por lo tanto, evitarán que se genere código.
fuente
Citando a Bjarne Stroustrup en TC ++ PL (Edición especial p.22):
fuente
D
hace. Si no desea la inicialización, utilice esta sintaxisfloat f = void;
oint* ptr = void;
. Ahora está inicializado de forma predeterminada, pero si realmente lo necesita, puede evitar que el compilador lo haga.Porque la inicialización lleva tiempo. Y en C ++, lo primero que debe hacer con cualquier variable es inicializarla explícitamente:
o:
o:
fuente
Porque uno de los lemas de C ++ es:
No pagas por lo que no usas
Por esta misma razón, el
operator[]
de lavector
clase no comprueba si el índice está fuera de los límites, por ejemplo.fuente
Por razones históricas, principalmente porque así es como se hace en C. Por qué se hace así en C, es otra cuestión, pero creo que el principio de cero gastos generales estuvo involucrado de alguna manera en esta decisión de diseño.
fuente
Además, tenemos una advertencia para cuando lo explote: "posiblemente se use antes de que se le asigne un valor" o verbage similar dependiendo de su compilador.
Compila con advertencias, ¿verdad?
fuente
Hay muy pocas situaciones en las que alguna vez tenga sentido que una variable no esté inicializada, y la inicialización predeterminada tiene un costo pequeño, entonces, ¿por qué hacerlo?
C ++ no es C89. Demonios, incluso C no es C89. Puede mezclar declaraciones y código, por lo que debe posponer la declaración hasta el momento en que tenga un valor adecuado para inicializar.
fuente
Un puntero es solo otro tipo. Si crea un tipo de POD
int
,char
o cualquier otro, no se inicializa a cero, entonces, ¿por qué debería hacerlo un puntero? Esto podría considerarse una sobrecarga innecesaria para alguien que escribe un programa como este.Si sabe que lo va a inicializar, ¿por qué debería incurrir en un costo el programa cuando crea por primera vez
pBuf
en la parte superior del método? Este es el principio de cero gastos generales.fuente
Si desea un puntero que siempre se inicialice en NULL, puede usar una plantilla de C ++ para emular esa funcionalidad:
fuente
Foo *a
usarInitializedPointer<Foo> a
: un ejercicio puramente académico, ya queFoo *a=0
es menos mecanografía. Sin embargo, el código anterior es muy útil desde un punto de vista educativo. Con una pequeña modificación (al ctor / dtor de "mantenimiento de posición" y las operaciones de asignación), podría extenderse fácilmente a varios tipos de punteros inteligentes, incluidos los punteros con alcance (que se liberan en el destructor) y los punteros contados de referencia agregando inc / dec operaciones cuando m_pPointer se establece o borra.Tenga en cuenta que los datos estáticos se inicializan en 0 (a menos que diga lo contrario).
Y sí, siempre debes declarar tus variables lo más tarde posible y con un valor inicial. Código como
debería hacer sonar las alarmas cuando lo lea. Sin embargo , no sé si se puede persuadir a alguna pelusa para que se queje, ya que es 100% legal.
fuente
Otra posible razón por la cual, es que en el momento del enlace, los punteros reciben una dirección, pero el direccionamiento / desreferenciación indirecto de un puntero es responsabilidad del programador. Por lo general, al compilador no le importa menos, pero la carga se pasa al programador para administrar los punteros y asegurarse de que no se produzcan pérdidas de memoria.
Realmente, en pocas palabras, se inicializan en el sentido de que en el momento del enlace se le da una dirección a la variable de puntero. En su código de ejemplo anterior, se garantiza que se bloqueará o generará un SIGSEGV.
En aras de la cordura, siempre inicialice los punteros a NULL, de esa manera si algún intento de desreferenciarlo sin
malloc
onew
indicará al programador la razón por la que el programa se comportó mal.Espero que esto ayude y tenga sentido,
fuente
Bueno, si C ++ inicializara los punteros, entonces la gente de C que se queja de "C ++ es más lento que C" tendría algo real a lo que aferrarse;)
fuente
C ++ proviene de un entorno C, y hay algunas razones que regresan de esto:
C, incluso más que C ++, es un reemplazo del lenguaje ensamblador. No hace nada que no le digas que haga. Por lo tanto: si desea NULARlo, ¡hágalo!
Además, si anula cosas en un lenguaje bare-metal como C, surgen automáticamente preguntas de coherencia: si mallociza algo, ¿debería ponerse a cero automáticamente? ¿Qué pasa con una estructura creada en la pila? ¿Deberían ponerse a cero todos los bytes? ¿Qué pasa con las variables globales? ¿qué pasa con una declaración como "(* 0x18);" ¿No significa eso entonces que la posición de memoria 0x18 debería ponerse a cero?
fuente
calloc()
.¿Cuáles son estos indicadores de los que habla?
Para la seguridad de excepción, siempre use
auto_ptr
,shared_ptr
,weak_ptr
y sus otras variantes.Un sello distintivo de un buen código es aquel que no incluye una sola llamada a
delete
.fuente
auto_ptr
y sustituyaunique_ptr
.Oh chico. La respuesta real es que es fácil poner a cero la memoria, que es la inicialización básica para, por ejemplo, un puntero. Lo que tampoco tiene nada que ver con la inicialización del objeto en sí.
Teniendo en cuenta las advertencias que la mayoría de los compiladores dan en los niveles más altos, no puedo imaginarme programando al nivel más alto y tratándolos como errores. Dado que subirlos nunca me ha salvado ni siquiera un error en grandes cantidades de código producido, no puedo recomendar esto.
fuente
NULL
, inicializarlo es un error.