2011-12-06 14 views
5

Sé que un destructor de mapas llama a cada uno de los destructores del elemento contenido. Lo que sucede por unastl map <char*,char*> destructor

map<char*,char*> ? 

no puedo ver donde esto es el código de /usr/include/c++/4.4


EDIT: que debería haber dicho

map<const char*, const char*, ltstr> 

al igual que en

http://www.sgi.com/tech/stl/Map.html

+4

Tenga en cuenta que un 'mapa' indexado por' char * 'probablemente no hará lo que quiera. Coincidirá en la dirección de la cadena, no en el contenido de la cadena. –

+0

En GCC 4.6 tiene que mirar adentro '/ usr/include/C++/4.6/bits/stl_map.h' y en 4.6 mirar adentro'/usr/include/C++/4.4/bits/stl_map.h' –

Respuesta

6

¿Qué ocurre

Nada. Si asignó dinámicamente la memoria, se filtrará: no hay un destructor automático para char*.

Use std::string o clase similar en su lugar.

+1

Bien, "nada" es probablemente un poco engañoso. Toda la memoria que el mapa asignó internamente para su árbol se elimina, después de todo. – sbi

+2

Creo que _technically_ tiene un destructor que no hace nada. (Puede llamar 'A-> ~ char *()') Pero el efecto es el mismo. –

14

Cuando se destruye map<char*,char*>, también lo están todos los elementos que contiene. Se llama al destructor de cada elemento, si es de tipo de clase.

Sin embargo, tenga en cuenta exactamente lo que figura en su mapa de arriba. No son cadenas, como es de esperar, solo son indicadores de cadenas. Las cuerdas en sí no son destruidas. Solo los punteros son delete nunca se llama en los punteros.

Caso en cuestión:

map<char*, char*> strings; 

char* key = new char[10]; 
char* value = new char[256]; 
/* ... */ 
strings.insert(key,value); 

En lo anterior, ya que delete Nunca se pidió a los punteros creados por las llamadas a new, esta memoria se fuga cuando strings sale del ámbito.

Esta es una buena ilustración de por qué debe evitar el uso de punteros sin procesar, new y delete. En su caso, map<string,string> probablemente sea una mejor opción.

EDIT:

Como @sbi mencionado en los comentarios, otra razón por la que usted quiere map<string,string> sobre map<char*,char*> es porque con map<string,string> claves se comparan por valor, en lugar de un triple-valor.

considerar:

#include <map> 
#include <iostream> 
#include <string> 
using namespace std; 

int main() 
{ 
    static const char MyKey[] = "foo"; 
    const char bar[] = "bar"; 
    typedef map<const char*,const char*> Strings; 
    Strings strings; 
    strings.insert(make_pair(MyKey,bar)); 

    string ss = "foo"; 
    Strings::const_iterator it = strings.find(ss.c_str()); 
    if(it == strings.end()) 
     cout << "Not Found!"; 
    else 
     cout << "Found"; 

} 

Fundamentalmente, vas a insertar un elemento con la clave "foo" y luego la búsqueda de ese elemento. Pruebe el código anterior y verá que no se encuentra. Sin embargo, si usted intenta esto:

#include <map> 
#include <iostream> 
#include <string> 
using namespace std; 

int main() 
{ 
    typedef map<string,string> Strings; 
    Strings strings; 
    strings.insert(make_pair("foo","bar")); 

    string ss = "foo"; 
    Strings::iterator it = strings.find(ss); 
    if(it == strings.end()) 
     cout << "Not Found~!"; 
    else 
     cout << "Found"; 
} 

... se obtiene el comportamiento que realmente querido.

+2

Excelente respuesta, '+ 1' de mi parte. Otra razón para preferir 'std :: string' es que en un' std :: map ', la clave se comparará con _address_, en lugar de con _content_. Pocas veces quieres eso. – sbi

+0

@sbi: Buen punto, editado. –

+0

+1 muy buena respuesta –

1

Estoy de acuerdo en que std::map<string, string> tendrá ventajas sobre std::map<char*, char*>.Especialmente tener la clave como valor en lugar de puntero proporcionaría los resultados esperados de búsqueda/búsqueda.

Pero, a veces necesitamos puntero en la definición de mapa, especialmente en la parte de valor cuando la parte de valor del mapa es un objeto pesado de una clase definida por el usuario. Por objeto pesado, quiero decir que el constructor de copias de la clase hace una gran cantidad de trabajo. En tales escenarios, la parte de valor del mapa debe ser un puntero. El uso de un puntero sin formato perdería la memoria como se mencionó anteriormente. El puntero inteligente sería una mejor opción para garantizar que no se filtre la memoria.

ejemplo muestra: en cuenta la clase de abajo

class ABCD 
{ 
public: 
    ABCD(const int ab) : a(ab) 
    {cout << "Constructing ABC object with value : " << a << endl;} 

    ~ABCD() 
    {cout << "Destructing ABC object with value : "<< a << endl;} 

    void Print() 
    { cout << "Value is : " << a << endl;} 

private: 
    int a; 
}; 

Considere el código donde en puntero inteligente de la clase anterior se utiliza:

{ 
    std::map<_tstring, std::shared_ptr<ABCD>> myMap; 
    _tstring key(_T("Key1")); 
    myMap.insert(std::make_pair(key, std::make_shared<ABCD>(10))); 
    auto itr = myMap.find(key); 
    itr->second->Print(); 

    myMap[key] = std::make_shared<ABCD>(20); 
    itr = myMap.find(key); 
    itr->second->Print(); 
} // myMap object is destroyed, which also calls the destructor of ABCD class 

salida desde arriba código es:

Constructing ABC object with value : 10 

Value is : 10 

Constructing ABC object with value : 20 

Destructing ABC object with value : 10 

Value is : 20 

Destructing ABC object with value : 20 
Cuestiones relacionadas