2009-03-29 13 views
65

See also C++ standard list and default-constructible typesPerché l'argomento del tipo di mappa C++ richiede un costruttore vuoto quando si utilizza []?

Non è un problema importante, solo fastidioso in quanto non voglio che la mia classe venga mai istanziata senza particolari argomenti.

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

map<int, MyClass> myMap; 

Questo mi dà il seguente errore g ++:

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

Questo compila bene se posso aggiungere un costruttore di default; Sono certo che non è causato da una sintassi errata.

+0

Il codice sopra compila bene su MinGW (g ++ 3.4.5) e MSVC++ 2008, a condizione che venga fornito un typedef per MyType e un punto e virgola aggiunto alla fine della classe. Devi fare qualcos'altro (ad esempio chiamando l'operatore [] come menzionato da bb) - per favore pubblica il codice * full *. –

+0

Ah, sì, hai ragione. Andrà bene. –

+0

Sì, senza l'utilizzo di myMap non si sa cosa debba essere compilato per la classe map. Anche il provider e la versione della libreria stl potrebbero essere d'aiuto. –

risposta

119

Questo problema viene fornito con operatore []. Citazione dalla documentazione 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() .

Se non si dispone di un costruttore predefinito, è possibile utilizzare le funzioni di inserimento/ricerca. Seguendo l'esempio funziona bene:

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

Risposta eccellente - nota anche 'emplace' in C++ 11 come alternativa concisa a' insert'. – prideout

+1

Perché 'std :: :: value_type' lì nella chiamata' insert'? – thomthom

+0

Perché il costruttore predefinito deve essere definito dall'utente? – schuess

6

Sì. I valori nei contenitori STL devono mantenere la semantica della copia. IOW, hanno bisogno di comportarsi come tipi primitivi (ad es. Int) il che significa, tra le altre cose, che dovrebbero essere costruttibili di default.

Senza questo (e altri requisiti) sarebbe inutilmente difficile implementare le varie operazioni interne di copia/spostamento/scambio/confronto sulle strutture di dati con cui sono implementati i contenitori STL.

In riferimento allo standard C++, vedo che la mia risposta non era accurata. Default-costruzione è, in realtà, non è un requisito:

Da 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 ...

Quindi, a rigor di termini, il vostro tipo di valore ha solo bisogno di essere costruibile default se vi capita di essere utilizzando una funzione del contenitore che utilizza il costruttore predefinito nella sua firma.

I requisiti reali (23.1.3) di tutti i valori memorizzati nei contenitori STL sono CopyConstructible e Assignable.

Esistono anche altri requisiti specifici per contenitori particolari, ad esempio Comparable (ad esempio per le chiavi in ​​una mappa).


Per inciso, il seguente compila senza errori sul comeau:

#include <map> 

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

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

Quindi questo potrebbe essere un problema g ++.

+2

Pensi che BB potrebbe fare qualcosa per quanto riguarda l'operatore []? –

+10

Questo codice probabilmente viene compilato perché non si sta chiamando myMap [] – jfritz42

-1

Verificare se:

  • hai dimenticato il ';' dopo la dichiarazione della classe.
  • MyType avrebbe dovuto essere dichiarato di conseguenza.
  • Nessun costruttore di default non vi ...

La dichiarazione std :: map sembra corretto, credo.

+0

Compila bene se aggiungo un costruttore predefinito. –

-1

Molto probabilmente perché std :: pair lo richiede. std :: pair contiene due valori utilizzando la semantica del valore, quindi è necessario essere in grado di creare un'istanza senza parametri. Quindi il codice usa std :: pair in varie posizioni per restituire i valori della mappa al chiamante e questo è comunemente fatto istanziando una coppia vuota e assegnandogli i valori prima di restituire la coppia locale.

È possibile aggirare questo con puntatori intelligenti utilizzando una mappa < int, smartptr < MyClass>> ma che aggiunge il sovraccarico di controllo per i puntatori nulli.

+2

+0. la coppia può essere usata bene con i tipi T e U privi di costruttori predefiniti - l'unica cosa che non può essere utilizzata in questo caso è il costruttore predefinito della coppia . Nessuna implementazione di qualità decente della mappa, , userebbe questo costruttore predefinito perché limita ciò che K e V possono essere. –

2

verificare i requisiti di tipo memorizzato del STL :: mappa. Molte raccolte di stl richiedono che il tipo memorizzato contenga alcune proprietà specifiche (costruttore predefinito, costruttore di copie, ecc.).

Il costruttore senza argomenti è necessario per la stl :: map, perché è utilizzato, quando l'operatore [] viene invocato con la chiave, che non è stata ancora mantenuta dalla mappa. In questo caso l'operatore [] inserisce la nuova voce costituita dalla nuova chiave e dal valore costruito utilizzando il costruttore senza parametri. E questo nuovo valore viene quindi restituito.

Problemi correlati