C ++ map access membuang qualifier (const)

113

Kode berikut mengatakan bahwa meneruskan peta constke dalam operator[]metode membuang qualifier:

#include <iostream>
#include <map>
#include <string>

using namespace std;

class MapWrapper {
public:
    const int &get_value(const int &key) const {
        return _map[key];
    }

private:
    map<int, int> _map;
};

int main() {
    MapWrapper mw;
    cout << mw.get_value(42) << endl;
    return 0;
}

Apakah ini karena kemungkinan alokasi yang terjadi pada akses peta? Apakah tidak ada fungsi dengan akses peta yang dideklarasikan sebagai const?

MapWrapper.cpp:10: error: passing ‘const std::map<int, int, std::less<int>, std::allocator<std::pair<const int, int> > >’ as ‘this’ argument of ‘_Tp& std::map<_Key, _Tp, _Compare, _Alloc>::operator[](const _Key&) [with _Key = int, _Tp = int, _Compare = std::less<int>, _Alloc = std::allocator<std::pair<const int, int> >]’ discards qualifiers

cdleary
sumber
Hanya sebuah nitpick, tetapi mw dapat dideklarasikan hanya sebagai MapWrapper mw;
Lukas
Poin bagus - Saya menulis dalam beberapa bahasa jadi saya cenderung menormalkan sintaks di seluruh bahasa sehingga semuanya sesuai di kepala saya. :)
cdleary
Saya bisa menghargai itu. Berhati-hatilah, dalam kasus seperti ini Anda memiliki konstruksi objek tambahan dan tugas yang tidak diperlukan.
Lukas
Poin bagus lainnya - mengandalkan operator penugasan default bukanlah praktik yang baik untuk contoh publik. ;)
cdleary

Jawaban:

152

std::map's operator []tidak dideklarasikan sebagai const, dan tidak bisa karena perilakunya:

T & operator [] (Const Key & key)

Mengembalikan referensi ke nilai yang dipetakan ke kunci yang setara dengan kunci, melakukan penyisipan jika kunci tersebut belum ada.

Akibatnya, fungsi Anda tidak dapat dideklarasikan const, dan menggunakan peta operator[].

std::map'sfind() fungsi memungkinkan Anda untuk mencari kunci tanpa memodifikasi peta.

find()mengembalikan iterator, atau const_iteratorke yang std::pairberisi kunci ( .first) dan nilai ( .second).

Di C ++ 11, Anda juga bisa menggunakan at()untuk std::map. Jika elemen tidak ada, fungsi melontarkan std::out_of_rangepengecualian, berbeda dengan operator [].

luke
sumber
8
tambahan: VALUE = map.find (KEY) -> detik; Saya harus belajar bahwa 'find ()' mengembalikan iterator, yang merupakan pasangan tipe.
FlipMcF
5
Saya akan menambahkan bahwa sekarang di C11 Anda dapat menggunakan: std :: map :: at (key) dan menghindari iterator.
Juan Besa
3
Menarik. Saya akan berpikir C ++ akan membedakan antara lvalue operator[](eg foo[bar] = baz) dan rvalue operator[](eg x = foo[bar]) - yang terakhir pasti bisa menjadi const.
Claudiu
15

Karena operator[]tidak memiliki kelebihan beban berkualifikasi const, kelebihan beban tidak dapat digunakan dengan aman dalam fungsi berkualifikasi const. Ini mungkin karena kelebihan beban saat ini dibuat dengan tujuan mengembalikan dan menetapkan nilai kunci.

Sebagai gantinya, Anda dapat menggunakan:

VALUE = map.find(KEY)->second;

atau, di C ++ 11, Anda dapat menggunakan at()operator:

VALUE = map.at(KEY);
Richard
sumber
map.find(KEY)->second; tidak aman jika nilai peta adalah string. Ini cenderung mencetak sampah jika KUNCI tidak ditemukan.
syam
1
Itu jawaban yang dijelaskan dengan benar yang langsung ke intinya. Kemarin saya menghabiskan 2 jam mencoba mencari tahu apa yang terjadi dengan kasus serupa. Bisakah kita setuju bahwa pesan kesalahan, paling banter, menyesatkan? Saya bisa lebih jelas jika tidak ada kata 'this' dan merujuk ke const-ness daripada qualifier yang lebih umum .
pengasuh
11

Anda tidak dapat menggunakan operator[]pada peta constkarena metode itu tidak constmemungkinkan Anda untuk memodifikasi peta (Anda dapat menetapkannya _map[key]). Coba gunakan findmetode ini sebagai gantinya.

nlativy
sumber
1
Dengan cara penjelasan: apa yang harus dilakukan operator [] peta jika kunci tidak ada? Jika peta adalah non-const, kuncinya ditambahkan dengan nilai bawaan yang dibuat. Jika peta const, apa yang bisa dikembalikan oleh operator []? Tidak ada nilai pada kunci itu.
Itu jawaban yang dijelaskan dengan benar yang langsung ke intinya. Kemarin saya menghabiskan 2 jam mencoba mencari tahu apa yang terjadi dengan kasus serupa. Bisakah kita setuju bahwa pesan kesalahan, paling banter, menyesatkan? Saya bisa lebih jelas jika tidak ada kata 'this' dan merujuk ke const-ness daripada qualifier yang lebih umum .
pengasuh
7

Beberapa versi terbaru dari header GCC (4.1 dan 4.2 pada mesin saya) memiliki fungsi anggota non-standar map :: at () yang dideklarasikan const dan membuang std :: out_of_range jika kuncinya tidak ada di peta.

const mapped_type& at(const key_type& __k) const

Dari referensi di komentar fungsi, tampaknya ini telah disarankan sebagai fungsi anggota baru di pustaka standar.

Nathan Kitchen
sumber
Saya rasa itu sedikit keanehan. Di-function adalah bagian dari standar yang akan datang, tetapi saya tidak menemukan at () di standar saat ini.
Sebastian Mach
'at' adalah bagian dari C ++ 11.
Étienne
0

Pertama, Anda tidak boleh menggunakan simbol yang diawali dengan _ karena simbol tersebut disediakan untuk implementasi bahasa / penulis kompilator. Akan sangat mudah bagi _map untuk menjadi kesalahan sintaks pada kompilator seseorang, dan Anda tidak akan menyalahkan siapa pun kecuali diri Anda sendiri.

Jika Anda ingin menggunakan garis bawah, letakkan di akhir, bukan di awal. Anda mungkin melakukan kesalahan ini karena Anda melihat beberapa kode Microsoft melakukannya. Ingat, mereka menulis kompiler mereka sendiri, jadi mereka mungkin bisa lolos begitu saja. Meski begitu, itu ide yang buruk.

operator [] tidak hanya mengembalikan referensi, tetapi juga membuat entri di peta. Jadi, Anda tidak hanya mendapatkan pemetaan, jika tidak ada, Anda membuatnya. Bukan itu yang Anda inginkan.

Dov
sumber
5
Maksud Anda tentang _salah. Pengenal yang dimulai dengan dua garis bawah ( __example) atau pengenal yang dimulai dengan satu garis bawah dan huruf kapital ( _Example) dicadangkan. _exampletidak dicadangkan.
Ethan