2010-07-13 21 views
10

Supongamos que alguna estructura de datos:referencia como clave en std :: mapa

typedef struct { 
    std::string s; 
    int i; 
} data; 

Si utilizo el campo data.s como clave a la hora de añadir los casos de data en un mapa de tipo std::map<std::string&, data>, hacer la cadena se copia? ¿Es seguro borrar un elemento del mapa porque la referencia se invalidará?

También las respuestas a estas preguntas también se aplican a un unordered_map?

EDIT:

Ésta es mi solución actual ... pero la adición de iterador para el mapa es FEO:

typedef struct { 
    const std::string* s; 
    int i; 
} data; 

std::map<std::string, data> map; 
typedef std::map<std::string, data>::iterator iterator; 

// add an element to the map 
iterator add_element(const std::string& s) { 
    std::pair<iterator, bool> p = states.insert(std::make_pair(s, data())); 
    iterator i = p.first; 
    if(p.second) { 
     data& d = (*i).second; 
     d.s = &(*i).first; 
    } 
    return i; 
} 

Respuesta

10

No se puede almacenar referencias en contenedores librería estándar - su mapa debe vea como:

map <string,data> mymap; 

El mapa administrará tanto la cadena de claves como las instancias de la estructura, que serán copias para usted. Tanto map como unordered_map funcionan de la misma manera a este respecto, al igual que todos los demás contenedores de la Biblioteca estándar.

Tenga en cuenta que en C++, no es necesario declarar typedefs estructuras:

struct data { 
    std::string s; 
    int i; 
}; 
+0

Gracias por la respuesta. Si quiero evitar tener dos copias de la cadena, ¿debería usar una referencia en la 'struct data' en su lugar? –

+1

Además, cuando dice que no puedo almacenar referencias, ¿quiere decir que el STL obliga a una copia? –

+2

@Helltone Las referencias son difíciles de usar correctamente como miembros de estructuras o clases; eso no es realmente para lo que estaban destinadas. En su lugar, debe usar un puntero u omitir la cadena de la estructura por completo. –

15

Es posible que desee echar un vistazo a boost.ref. Se proporciona un contenedor que permite referencias a utilizar en STL contenedores como esto:

std::map<boost::reference_wrapper<std::string>, data> 

Como de C++ 11, esto es parte de la norma (antes de que, los compiladores que implementan TR1 también ofrecen en el espacio de nombres std::tr1).

0

No puede usar la referencia. El mapa puede copiar el contenido. Supongo que esto depende de la implementación.

Pero probado con microsoft STL.

struct data 
{ 
      data(data const& rhs) 
      { 
       a new object will be created here 
      } 
      std::string s; 
      int i; 
}; 

Agregue algunos objetos al mapa y se encontrará con el constructor de copia. Esto debería invalidar su referencia.

0

No creo que haya una gran ganancia de rendimiento si elige el puntero en lugar del objeto. Solo haga esto si está administrando datos con muchos objetos de cadena existentes que deben contenerse dentro del contenedor. Además, la destrucción de los objetos debe ser gestionada manualmente antes de destruir el contenedor.

Cuestiones relacionadas