Wymyślony przykład, aby odpowiedzieć na pytanie:
void MyClass::MyFunction( int x ) const
{
std::cout << m_map[x] << std::endl
}
To się nie skompiluje, ponieważ operator [] nie jest stałą.
Jest to niefortunne, ponieważ składnia [] wygląda bardzo czysto. Zamiast tego muszę zrobić coś takiego:
void MyClass::MyFunction( int x ) const
{
MyMap iter = m_map.find(x);
std::cout << iter->second << std::endl
}
To zawsze mnie wkurza. Dlaczego operator [] nie jest stałą?
operator[]
dać, gdy dany element nie istnieje?Odpowiedzi:
For
std::map
andstd::unordered_map
,operator[]
wstawi wartość indeksu do kontenera, jeśli wcześniej nie istniała. To trochę nieintuicyjne, ale tak właśnie jest.Ponieważ musi mieć możliwość niepowodzenia i wstawienia wartości domyślnej, operatora nie można używać na
const
wystąpieniu kontenera.http://en.cppreference.com/w/cpp/container/map/operator_at
źródło
std::set
nie maoperator[]
.std::vector
ma odczytu operatora[]
, który jestconst
.map
powinien zrobić to samo.Teraz z C ++ 11 możesz mieć czystszą wersję używając at ()
void MyClass::MyFunction( int x ) const { std::cout << m_map.at(x) << std::endl; }
źródło
map
masz const i non-constat()
s - dlaczego nie to samo również dlaoperator[]
? z wersją const nic nie wstawia, tylko rzuca? (Lub zwracanie opcjonalnego, gdy std :: optional robi to w standardzie)at
występuje w dwóch odmianach, jest to, że robi areturn *this;
, a jedyną różnicą między przeciążeniami jestconst
-ness zwróconego odwołania. Rzeczywiste skutki obu efektówat
są dokładnie takie same (to znaczy brak efektu).Uwaga dla nowych czytelników.
Pierwotne pytanie dotyczyło kontenerów STL (a nie konkretnie std :: map)
Należy zauważyć, że na większości kontenerów istnieje wersja const operatora [].
Po prostu std :: map i std :: set nie mają wersji const i jest to wynikiem podstawowej struktury, która je implementuje.
Z std :: vector
reference operator[](size_type n) const_reference operator[](size_type n) const
Również w drugim przykładzie powinieneś sprawdzić, czy nie udało się znaleźć elementu.
void MyClass::MyFunction( int x ) const { MyMap iter = m_map.find(x); if (iter != m_map.end()) { std::cout << iter->second << std::endl } }
źródło
std::set
w ogóle nie maoperator[]
.Ponieważ operator [] może wstawić nowy element do kontenera, nie może to być stała funkcja składowa. Zauważ, że definicja operatora [] jest niezwykle prosta: m [k] jest równoważne z (* ((m.wstaw (typ_wartości (k, typ_danych ())). Pierwsza)). Sekunda. Ściśle mówiąc, ta funkcja członkowska jest niepotrzebna: istnieje tylko dla wygody
źródło
Operator indeksu powinien być stały tylko dla kontenera tylko do odczytu (który tak naprawdę nie istnieje w STL jako taki).
Operatory indeksu służą nie tylko do sprawdzania wartości.
źródło
const
, drugiej nieconst
- jak npstd::vector
.Jeśli zadeklarujesz zmienną składową std :: map jako mutowalną
mutable std::map<...> m_map;
możesz użyć funkcji składowych niebędących stałymi std :: map w ramach funkcji składowych stałych.
źródło
mutable
może być używany dla członków, takich jakstd::mutex
pamięci podręczne i pomocnicy debugowania. Jeśli mapa ma być używana jako pamięć podręczna w celu przyspieszenia bardzo kosztownej funkcjiconst
„pobierającej”, tomutable
jest to dopuszczalne. Trzeba być ostrożnym, ale sam w sobie nie jest to straszny pomysł.