C ++ harita erişimi niteleyicileri atar (const)


113

Aşağıdaki kod, haritayı yönteme göre geçirmenin niteleyicileri constattığını söylüyor operator[]:

#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;
}

Bu, harita erişiminde meydana gelen olası tahsis nedeniyle mi? Harita erişimli hiçbir işlev sabit olarak bildirilemez mi?

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


Sadece bir nitpick, ancak mw sadece MapWrapper mw olarak bildirilebilir;
luke

İyi bir nokta - birkaç dilde yazıyorum, bu yüzden söz dizimini normalleştirme eğilimindeyim, böylece hepsi kafama uyuyor. :)
cdleary

Bunu takdir edebilirim. Yine de dikkatli olun, bunun gibi durumlarda gerekli olmayan ekstra bir nesne yapınız ve göreviniz var.
luke

Bir başka iyi nokta - varsayılan atama operatörüne güvenmek, genel örnekler için iyi bir uygulama değildir. ;)
cdleary

Yanıtlar:


152

std::map's operator []olarak bildirilmez constve davranışından kaynaklanamaz:

T & operatör [] (sabit Anahtar ve anahtar)

Anahtara eşdeğer bir anahtara eşlenen değere bir başvuru döndürür ve böyle bir anahtar zaten mevcut değilse ekleme gerçekleştirir.

Sonuç olarak, işleviniz bildirilemez constve haritaların işlevini kullanamaz operator[].

std::map'ınfind() işlevi, haritayı değiştirmeden bir tuşa bakmanıza izin verir.

find()kullanıcıya bir iteratorveya const_iteratorbir üzere std::pairanahtarı (her ikisini de içeren .first) ve değer ( .second).

C ++ 11, ayrıca kullanabilirsiniz at()için std::map. Eleman yoksa, fonksiyonun std::out_of_rangetersine bir istisna atar operator [].


8
ek olarak: VALUE = map.find (KEY) -> saniye; 'Find ()' türünün bir yineleyici döndürdüğünü öğrenmem gerekiyordu, bu tür çifti.
FlipMcF

5
Şimdi C11'de şunu ekleyeceğim: std :: map :: at (key) ve yineleyiciden kaçınabilirsiniz.
Juan Besa

3
İlginç. C ++ 'nın lvalue operator[](örn. foo[bar] = baz) Ve rvalue operator[](örn. x = foo[bar]) Arasında ayrım yapacağını düşünürdüm - ikincisi kesinlikle const olabilir.
Claudiu

15

Dan beri operator[] bir const nitelikli aşırı yoktur, güvenle bir const nitelikli işlevinde kullanılamaz. Bunun nedeni büyük olasılıkla mevcut aşırı yükün hem geri dönme hem de anahtar değerleri ayarlama amacıyla oluşturulmuş olmasıdır.

Bunun yerine şunları kullanabilirsiniz:

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

veya C ++ 11'de at()operatörü kullanabilirsiniz :

VALUE = map.at(KEY);

map.find(KEY)->second; harita değerleri dizeler olduğunda güvenli değildir. KEY bulunamadığında çöp basma eğilimindedir.
syam

1
Bu, noktaya kadar doğru şekilde açıklanmış bir cevap. Dün benzer bir vakada neler olup bittiğini anlamak için 2 saatimi harcadım. Hata mesajının en iyi ihtimalle yanıltıcı olduğunu kabul edebilir miyiz? Eğer 'bu' kelimesine sahip olmasaydı ve daha genel niteleyici yerine sabitliğe atıfta bulunsaydı daha net olabilirdim .
carnicer

11

operator[]Bir haritada kullanamazsınız , constçünkü bu yöntem constharitayı değiştirmenize izin vermez (atayabilirsiniz _map[key]). findBunun yerine yöntemi kullanmayı deneyin .


1
Açıklama yolu ile: Anahtar mevcut değilse haritanın operatörü [] ne yapmalıdır? Harita const değilse, anahtar varsayılan oluşturulmuş değerle eklenir. Harita sabit ise, [] işleci tarafından ne döndürülebilir? O anahtarda değer yok.

Bu, noktaya kadar doğru şekilde açıklanmış bir cevap. Dün benzer bir vakada neler olup bittiğini anlamak için 2 saatimi harcadım. Hata mesajının en iyi ihtimalle yanıltıcı olduğunu kabul edebilir miyiz? Eğer 'bu' kelimesine sahip olmasaydı ve daha genel niteleyici yerine sabitliğe atıfta bulunsaydı daha net olabilirdim .
carnicer

7

GCC başlıklarının bazı yeni sürümleri (makinemde 4.1 ve 4.2) standart olmayan üye işlevlere sahiptir: map :: at (), bunlar const olarak bildirilir ve anahtar haritada değilse std :: out_of_range atar.

const mapped_type& at(const key_type& __k) const

İşlevin yorumundaki bir referanstan, bunun standart kitaplıkta yeni bir üye işlevi olarak önerildiği görülmektedir.


Sanırım bu biraz tuhaf. At-işlevi yaklaşan standardın bir parçası, ancak mevcut standartta at () 'ı bulamıyorum.
Sebastian Mach

'at', C ++ 11'in bir parçasıdır.
Étienne

0

İlk olarak, _ ile başlayan sembolleri kullanmamalısınız çünkü bunlar dil uygulamasına / derleyici yazıcısına ayrılmıştır. _Map için birinin derleyicisinde bir sözdizimi hatası olması çok kolay olurdu ve sizden başka suçlayacak kimseniz olmazdı.

Alt çizgi kullanmak istiyorsanız, başlangıca değil sonuna koyun. Muhtemelen bu hatayı, bunu yapan bazı Microsoft kodlarını gördüğünüz için yaptınız. Unutmayın, kendi derleyicilerini yazarlar, böylece ondan sıyrılabilirler. Öyle olsa bile, bu kötü bir fikir.

[] operatörü yalnızca bir referans döndürmekle kalmaz, aynı zamanda haritada girişi de oluşturur. Yani sadece bir eşleme almıyorsunuz, eğer yoksa, bir tane oluşturuyorsunuz. Amaçladığın bu değil.


5
Senin fikrin _sadece yanlış. İki alt çizgi ( __example) ile başlayan tanımlayıcılar veya bir alt çizgi ve bir büyük harf ( _Example) ile başlayan tanımlayıcılar ayrılır. _examplerezerve edilmemiştir.
Ethan
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.