Mengapa bukan operator [] const untuk peta STL?

89

Contoh yang dibuat-buat, demi pertanyaan:

void MyClass::MyFunction( int x ) const
{
  std::cout << m_map[x] << std::endl
}

Ini tidak akan bisa dikompilasi, karena operator [] adalah non-const.

Ini sangat disayangkan, karena sintaks [] terlihat sangat bersih. Sebaliknya, saya harus melakukan sesuatu seperti ini:

void MyClass::MyFunction( int x ) const
{
  MyMap iter = m_map.find(x);
  std::cout << iter->second << std::endl
}

Ini selalu mengganggu saya. Mengapa operator [] bukan konstanta?

Runcible
sumber
5
Apa yang harus operator[]dihasilkan jika elemen yang diberikan tidak ada?
Frerich Raabe
4
@Frerich Raabe: Hal yang sama dengan fungsi anggota at: throw std :: out_of_range
Jean-Simon Brochu

Jawaban:

90

Untuk std::mapdan std::unordered_map, operator[]akan memasukkan nilai indeks ke dalam wadah jika sebelumnya tidak ada. Ini sedikit tidak intuitif, tapi begitulah adanya.

Karena harus dibiarkan gagal dan memasukkan nilai default, operator tidak dapat digunakan pada constinstance penampung.

http://en.cppreference.com/w/cpp/container/map/operator_at

Alan
sumber
3
std::settidak punya operator[].
avakar
2
Itu adalah jawaban yang benar, tetapi versi const dapat melakukan hal yang sama seperti anggota "at". Itu melempar std :: out_of_range ...
Jean-Simon Brochu
Saat digunakan untuk membaca nilai, tidak ada nilai default yang disediakan. std::vectormemiliki operator membaca []yang const. mapharus melakukan hal yang sama.
wcochran
51

Sekarang dengan C ++ 11 Anda dapat memiliki versi yang lebih bersih dengan menggunakan at ()

void MyClass::MyFunction( int x ) const
{
  std::cout << m_map.at(x) << std::endl;
}
Deqing
sumber
4
Jika mapmemiliki const dan non-const at()s - mengapa tidak sama juga untuk operator[]? dengan versi const tidak memasukkan apa-apa melainkan melempar? (Atau mengembalikan opsional, ketika std :: opsional menjadikannya standar)
einpoklum
@einpoklum Inti dari kebenaran const sebagian besar adalah pemeriksaan waktu kompilasi statis. Saya lebih suka kompilator mengeluh daripada melempar pengecualian karena saya tidak menggunakan objek const dengan benar.
Millie Smith
@einpoklum Sangat terlambat, tetapi untuk pembaca lain: memiliki dua kelebihan melakukan hal yang berbeda akan sangat buruk. Satu-satunya alasan atdatang dalam dua ragam adalah karena ia melakukan a return *this;, dan satu-satunya perbedaan antara kelebihan beban adalah const-ness dari referensi yang dikembalikan. Efek sebenarnya dari keduanya atsama persis (yaitu, tidak ada efek).
HTNW
28

Catatan untuk pembaca baru.
Pertanyaan asli adalah tentang kontainer STL (tidak secara khusus tentang std :: map)

Perlu dicatat bahwa ada versi const dari operator [] di sebagian besar penampung.
Hanya saja std :: map dan std :: set tidak memiliki versi const dan ini adalah hasil dari struktur dasar yang mengimplementasikannya.

Dari std :: vector

reference       operator[](size_type n) 
const_reference operator[](size_type n) const 

Juga untuk contoh kedua Anda, Anda harus memeriksa kegagalan untuk menemukan elemen tersebut.

void MyClass::MyFunction( int x ) const
{
    MyMap iter = m_map.find(x);
    if (iter != m_map.end())
    {
        std::cout << iter->second << std::endl
    }
}
Martin York
sumber
1
std::settidak punya operator[]sama sekali.
Semua orang
2

Karena operator [] mungkin memasukkan elemen baru ke dalam wadah, itu tidak mungkin menjadi fungsi anggota const. Perhatikan bahwa definisi operator [] sangat sederhana: m [k] setara dengan (* ((m.insert (value_type (k, data_type ()))). First)). Second. Sebenarnya, fungsi anggota ini tidak diperlukan: ini hanya ada untuk kenyamanan

Satbir
sumber
0

Operator indeks seharusnya hanya menjadi const untuk penampung hanya-baca (yang sebenarnya tidak ada di STL).

Operator indeks tidak hanya digunakan untuk melihat nilai.

Nick Bedford
sumber
6
Pertanyaannya adalah, mengapa tidak memiliki dua versi yang kelebihan beban - satu const, yang lain bukan const- seperti std::vectorhalnya.
Pavel Minaev
-2

Jika Anda mendeklarasikan variabel std :: map member Anda menjadi bisa berubah

mutable std::map<...> m_map;

Anda dapat menggunakan fungsi anggota non-const dari std :: map dalam fungsi anggota const Anda.

Anthony Cramp
sumber
15
Ini ide yang buruk.
GManNickG
7
API untuk kelas Anda ada jika Anda melakukan itu. Fungsi tersebut mengklaim bahwa itu adalah const - artinya ia tidak akan mengubah variabel anggota apa pun - tetapi pada kenyataannya ia mungkin memodifikasi anggota data m_map.
Runcible
2
mutabledapat digunakan untuk anggota seperti std::mutex, cache dan pembantu debug. Jika peta akan digunakan sebagai cache untuk mempercepat constfungsi "pengambil" yang sangat mahal , maka mutableitu dapat diterima. Anda perlu berhati-hati, tetapi itu sendiri bukanlah ide yang buruk.
Mark Lakata