2009-03-29 15 views
65

See also C++ standard list and default-constructible types¿Por qué el argumento del tipo de mapa C++ requiere un constructor vacío cuando se usa []?

No es un problema importante, solo molesto ya que no quiero que mi clase sea instanciada alguna vez sin los argumentos particulares.

class MyClass 
{ 
public: 
    MyClass(MyType1 t); 
    MyType2 &operator[](int index); 
} 

map<int, MyClass> myMap; 

Esto me da el siguiente error g ++:

/usr/include/c++/4.3/bits/stl_map.h:419: error: no matching function for call to ‘MyClass()’

Este compila bien si agrego un constructor por defecto; Estoy seguro de que no se debe a una sintaxis incorrecta.

+0

El código anterior compila muy bien en MinGW (g ++ 3.4.5) y MSVC++ 2008, siempre que se proporcione un typedef para MyType y un punto y coma agregado al final de la clase. Debe estar haciendo otra cosa (por ejemplo, llamar al operador [] según lo mencionado por bb); publique el código * completo *. –

+0

Ah, sí, tienes razón. Hará. –

+0

Sí, sin el uso de myMap no sabes qué se debe compilar para la clase de mapa. ¿Qué proveedor de la biblioteca stl y la versión también podría ayudar. –

Respuesta

119

Este problema viene con el operador []. Cita de la documentación de SGI:

data_type& operator[](const key_type& k) - Returns a reference to the object that is associated with a particular key. If the map does not already contain such an object, operator[] inserts the default object data_type() .

Si no tiene un constructor predeterminado, puede usar las funciones de inserción/búsqueda. Siguiendo el ejemplo funciona bien:

myMap.insert(std::map< int, MyClass >::value_type (1, MyClass(1))); 
myMap.find(1)->second; 
+8

Respuesta excelente: tenga en cuenta también "emplace" en C++ 11 como alternativa alternativa a "insertar". – prideout

+1

¿Por qué 'std :: :: value_type' está allí en la llamada' insert'? – thomthom

+0

¿Por qué el constructor predeterminado necesita ser definido por el usuario? – schuess

6

Sí. Los valores en los contenedores STL necesitan mantener la semántica de copia. IOW, necesitan comportarse como tipos primitivos (por ejemplo, int) lo que significa, entre otras cosas, que deben ser predecibles.

Sin esto (y otros requisitos) sería innecesariamente difícil implementar las diversas operaciones internas de copiar/mover/intercambiar/comparar en las estructuras de datos con las que se implementan los contenedores STL.

Al hacer referencia al Estándar C++, veo que mi respuesta no era precisa. predeterminado-construcción es, de hecho, no es un requisito:

De 20.1.4.1:

The default constructor is not required. Certain container class member function signatures specify the default constructor as a default argument. T() must be a well-defined expression ...

Por lo tanto, en sentido estricto, el tipo de valor sólo tiene que ser construible por defecto si se esté utilizando una función del contenedor que utiliza el constructor predeterminado en su firma.

Los requisitos reales (23.1.3) de todos los valores almacenados en contenedores STL son CopyConstructible y Assignable.

También existen otros requisitos específicos para contenedores particulares, como Comparable (por ejemplo, para las claves de un mapa).


Por cierto, el siguiente compila sin error en comeau:

#include <map> 

class MyClass 
{ 
public: 
    MyClass(int t); 
}; 

int main() 
{ 
    std::map<int, MyClass> myMap; 
} 

lo que este podría ser un g ++ problema.

+2

¿Cree que BB podría estar relacionado con algo relacionado con el operador []? –

+10

Ese código probablemente se compila porque no está llamando a myMap [] – jfritz42

-1

Comprobar si:

  • se le olvidó la ';' después de la declaración de clase.
  • MyType debería haberse declarado en consecuencia.
  • Sin constructor por defecto no ...

La declaración std :: mapa parece correcta, creo.

+0

Compila bien si agrego un constructor predeterminado. –

-1

Probablemente porque std :: pair lo requiere. std :: pair contiene dos valores usando la semántica de valores, por lo que debe poder crear instancias sin parámetros. Entonces, el código usa std :: pair en varios lugares para devolver los valores del mapa a la persona que llama, y ​​esto se hace comúnmente instanciando un par vacío y asignándole los valores antes de devolver el par local.

Puede solucionar esto con punteros inteligentes usando un mapa < int, smartptr < MyClass>> pero eso agrega la sobrecarga de buscar punteros nulos.

+2

+0. el par se puede usar muy bien con los tipos T y U que carecen de constructores predeterminados; lo único que no se puede usar en este caso es el constructor predeterminado del par . Ninguna implementación de calidad decente del mapa usaría este constructor predeterminado porque limita lo que K y V pueden ser. –

2

comprobar los requisitos de tipo almacenado de la STL :: mapa. Muchas colecciones stl requieren que el tipo almacenado contenga algunas propiedades específicas (constructor predeterminado, constructor de copia, etc.).

El stl :: map necesita un constructor sin argumentos, porque se usa cuando el operador [] se invoca con la tecla, que no ha sido conservada por el mapa. En este caso, el operador [] inserta la nueva entrada que consiste en la nueva clave y el valor construido usando un constructor sin parámetros. Y este nuevo valor es devuelto.

Cuestiones relacionadas