2009-03-29 13 views
65

See also C++ standard list and default-constructible typesDlaczego argument typu mapy C++ wymaga pustego konstruktora podczas używania []?

Nie jest to poważny problem, tylko denerwujący, ponieważ nie chcę, aby moja klasa była kiedykolwiek tworzona bez konkretnych argumentów.

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

map<int, MyClass> myMap; 

To daje mi następujący błąd g ++:

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

To kompiluje w porządku, jeśli dodam domyślnego konstruktora; Jestem pewien, że nie jest to spowodowane nieprawidłową składnią.

+0

Powyższy kod kompiluje się poprawnie na MinGW (g ++ 3.4.5) i MSVC++ 2008, pod warunkiem, że podano typedef dla MyType i średnik dołączony do końca klasy. Musisz robić coś innego (np. Dzwoniąc do operatora [] jak wspomniano w bb) - opublikuj * pełny * kod. –

+0

Ach, tak, masz rację. Zrobi to. –

+0

Tak, bez użycia myMap nie wiesz, co trzeba skompilować dla klasy mapy. Którego dostawcę biblioteki biblioteki i wersja może również pomóc. –

Odpowiedz

119

Ten problem pochodzi z operatora []. Cytat z dokumentacji 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() .

Jeśli nie masz domyślnego konstruktora, możesz użyć funkcji wstawiania/szukania. poniższym przykładzie działa prawidłowo:

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

Doskonała odpowiedź - zwróć uwagę także na 'emplace' w C++ 11 jako zwięzłą alternatywę dla' insert'. – prideout

+1

Dlaczego jest to 'std :: :: value_type' w wywołaniu' insert'? – thomthom

+0

Dlaczego domyślny konstruktor musi być zdefiniowany przez użytkownika? – schuess

6

Tak. Wartości w kontenerach STL muszą zachować semantykę kopiowania. IOW, muszą zachowywać się jak prymitywne typy (na przykład int), co oznacza, między innymi, że powinny być domyślne - konstruktywne.

Bez tego (i innych wymagań) byłoby niepotrzebnie trudne wdrażanie różnych wewnętrznych operacji kopiowania/przenoszenia/wymiany/porównywania struktur danych, w których zaimplementowano kontenery STL.

Po odwołaniu do standardu C++ widzę, że moja odpowiedź nie była dokładna. Default-budowlany jest w rzeczywistości, a nie wymóg:

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

Tak, ściśle rzecz biorąc, tylko typ wartości musi być domyślnym constructible jeśli zdarzy ci się być za pomocą funkcja kontenera, który używa domyślnego konstruktora w swoim podpisie.

Rzeczywistymi wymaganiami (23.1.3) ze wszystkich wartości przechowywanych w pojemnikach STL są CopyConstructible i Assignable.

Istnieją również inne szczególne wymagania dla poszczególnych pojemników, na przykład Comparable (np. Dla kluczy na mapie).


Nawiasem mówiąc, co następuje kompiluje bez błędów na comeau:

#include <map> 

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

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

Więc może to być g ++ problem.

+2

Czy myślisz, że bb może być na czymś w stosunku do operatora []? –

+10

Ten kod prawdopodobnie się kompiluje, ponieważ nie wywołujesz myMap [] – jfritz42

-1

Sprawdź, czy:

  • zapomniałeś ';' po deklaracji klasy.
  • MyType powinien zostać odpowiednio zadeklarowany.
  • Nie domyślny konstruktor tam ...

Deklaracja std :: map wydaje się poprawne, myślę.

+0

Kompiluje dobrze, jeśli dodaję domyślny konstruktor. –

-1

Najprawdopodobniej dlatego, że wymaga tego std :: pair. std :: pair przechowuje dwie wartości używając semantyki wartości, więc musisz mieć możliwość tworzenia ich bez parametrów. Tak więc kod używa std :: pair w różnych miejscach, aby zwrócić wartości mapy do wywołującego i jest to zwykle robione przez utworzenie pustej pary i przypisanie jej wartości przed zwróceniem pary lokalnej.

Można obejść ten problem inteligentnymi wskaźnikami, korzystając z mapy < int, smartptr < MyClass>>, ale to zwiększa obciążenie związane z sprawdzaniem wskaźników zerowych.

+2

+0. Para może być używana bez problemów z typami T i U bez domyślnych konstruktorów - jedyną rzeczą, której nie można użyć w tym przypadku, jest domyślny konstruktor pary . Żadna przyzwoitej jakości implementacja mapy nie użyje tego domyślnego konstruktora, ponieważ ogranicza to, czym mogą być K i V. –

2

Sprawdź wymagania przechowywanych typu STL :: mapie. Wiele kolekcji STL wymaga, aby typ przechowywany zawierał pewne specyficzne właściwości (domyślny konstruktor, konstruktor kopii itp.).

Konstruktor bez argumentów jest wymagany przez stl :: map, ponieważ jest używany, gdy operator [] jest wywoływany za pomocą klucza, który nie był już przechowywany na mapie. W tym przypadku operator [] wstawia nowy wpis składający się z nowego klucza i wartości skonstruowanej przy użyciu konstruktora bez parametrów. I ta nowa wartość jest następnie zwracana.

Powiązane problemy