2009-06-01 25 views
27

tengo código como este:¿Cuál es el constructor predeterminado para el puntero de C++?

class MapIndex 
{ 
private: 
    typedef std::map<std::string, MapIndex*> Container; 
    Container mapM; 

public: 
    void add(std::list<std::string>& values) 
    { 
     if (values.empty()) // sanity check 
      return; 

     std::string s(*(values.begin())); 
     values.erase(values.begin()); 
     if (values.empty()) 
      return; 

     MapIndex *mi = mapM[s]; // <- question about this line 
     if (!mi) 
      mi = new MapIndex(); 
     mi->add(values); 
    } 
} 

La principal preocupación que tengo es si el mapm [s] expresión devolvería referencia a puntero nulo si se añade nuevo elemento al mapa?

El SGI docs decir esto: data_type & operador [] (key_type const & k) Devuelve una referencia al objeto que está asociado con una clave particular. Si el mapa aún no contiene dicho objeto, el operador [] inserta el objeto predeterminado tipo_datos().

Por lo tanto, mi pregunta es si la inserción de objeto data_type predeterminado() creará un puntero NULL, o podría crear un puntero no válido apuntando en algún lugar de la memoria?

Respuesta

20

Se creará un (0) NULL puntero, que es un puntero no válido de todos modos :)

+5

No me importa que no sea válido, pero quiero que sea "seguro". Puede verificar fácilmente 0 puntero y puede llamar "eliminar" en él. ¿Alguna referencia (URL) para leer sobre esto? –

+0

No tengo una referencia a mano. Pero estoy bastante seguro de que un constructor de puntero lo inicializará en 0 (al igual que todos los tipos integrales, como 'int',' short', ...). –

+20

C++ Standard, 8.5 párrafo 5: 'Para inicializar por defecto un objeto de tipo T significa: de lo contrario (ni no POD ni matriz), el objeto se inicializa en cero.' Solo unas líneas arriba: 'Inicializar a cero un objeto de tipo T significa: si T es un tipo escalar (3.9), el objeto se establece en el valor de 0 (cero) convertido a T;' En la misma norma, 3.9, párrafo 10: 'Tipos aritméticos (3.9.1), tipos de enumeración, tipos de puntero y puntero a tipos de miembro (3.9.2), [...] se denominan colectivamente tipos escalares'. Así que sí, un puntero se inicializará por defecto a 0. –

2

La expresión data_type() evalúa a un objeto predeterminado-inicializado. En el caso de los tipos que no son POD, se invoca el constructor predeterminado, pero en el caso de los tipos de POD, como los punteros, la inicialización predeterminada es equivalente a la inicialización cero.

Así que sí, puede confiar en su mapa creando un puntero NULL. Para obtener una explicación, puede consultar Pseudo Constructor Initializers.

18

Sí, debería ser un puntero cero (NULL) ya que los contenedores STL inicializarán por defecto objetos cuando no estén almacenados explícitamente (es decir, accediendo a una clave inexistente en un mapa como lo está haciendo o redimensionando un vector a un tamaño mayor tamaño).

C++ estándar, 8,5 párrafo 5 estados:

Para default-inicializar un objeto de tipo T significa:

  • Si T es un tipo de clase no-POD (clase cláusula), se llama al constructor predeterminado para T (y la inicialización está mal formada si T tiene sin constructor predeterminado accesible)
  • Si T es un tipo de matriz, cada elemento está predeterminado -inicializado
  • De lo contrario, el almacenamiento para el objeto se inicializa en cero.

También debe tener en cuenta que la inicialización por defecto es diferente a simplemente ommiting el constructor. Cuando omite el constructor y simplemente declara un tipo simple obtendrá un valor indeterminado.

int a; // not default constructed, will have random data 
int b = int(); // will be initialised to zero 
3

ACTUALIZACIÓN: Yo completé mi programa y esa misma línea que estaba preguntando acerca está causando que se caiga a veces, pero en una etapa posterior. El problema es que estoy creando un nuevo objeto sin cambiar el puntero almacenado en std :: map. Lo que realmente se necesita es referencia o puntero a ese puntero.

MapIndex *mi = mapM[s]; // <- question about this line 
if (!mi) 
    mi = new MapIndex(); 
mi->add(values); 

se debe cambiar a:

MapIndex* &mi = mapM[s]; // <- question about this line 
if (!mi) 
    mi = new MapIndex(); 
mi->add(values); 

me sorprende que nadie se dio cuenta de esto.

0

No estoy seguro sobre el accidente, pero definitivamente pérdida de memoria ya que esta declaración

si (mi!) mi = nueva MapIndex();

siempre devuelve verdadero, porque el puntero mi no es referencia de lo que mapM tiene en cuenta para un valor particular de s.

También evitaría el uso de punteros regulares y usar boost :: shared_ptr o algún otro otro puntero que libera memoria cuando se destruye. Esto permite llamar a mapM.clear() o borrar() que debe llamar a destructores de claves y valores almacenados en el mapa. Bueno, si el valor es POD como su puntero, entonces no se llamará a ningún destructor a menos que se elimine manualmente mientras se itera a través de un mapa completo y se producen fugas de memoria.

Cuestiones relacionadas