STL haritaları için [] operatörü sabiti neden değil?


90

Sorunun uğruna uydurma örnek:

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

[] Operatörü sabit olmadığı için bu derlenmez.

[] Sözdizimi çok temiz göründüğü için bu talihsiz bir durumdur. Bunun yerine şöyle bir şey yapmalıyım:

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

Bu her zaman beni rahatsız etti. [] Operatörü neden const değil?


5
operator[]Verilen elemanın olmaması durumunda ne vermelidir ?
Frerich Raabe

5
@Frerich Raabe: at üye işlevi ile aynı şey: throw std :: out_of_range
Jean-Simon Brochu

Yanıtlar:


91

İçin std::mapve std::unordered_map, operator[]daha önce olmasaydı kabın içine endeksi değerini ekler. Biraz sezgisel değil, ama bu böyle.

Başarısız olmasına ve varsayılan bir değer girmesine izin verilmesi gerektiğinden, operatör constkabın bir örneğinde kullanılamaz .

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


3
std::setsahip değil operator[].
avakar

2
Doğru cevap budur, ancak bir const sürümü "at" üyesiyle aynı şeyi yapabilir. Bu bir std atmak :: out_of_range ...
Jean-Simon Brochu

Bir değeri okumak için kullanıldığında, sağlanacak varsayılan bir değer yoktur. std::vectorolan bir okuma operatörüne []sahiptir const. mapaynısını yapmalı.
wcochran

52

Artık C ++ 11 ile () kullanarak daha temiz bir sürüme sahip olabilirsiniz.

void MyClass::MyFunction( int x ) const
{
  std::cout << m_map.at(x) << std::endl;
}

4
mapSabit ve sabit olmayanlar varsa at()- neden aynı şey olmasın operator[]? const sürümü hiçbir şey eklemiyor, daha çok fırlatıyor mu? (Ya da std :: isteğe bağlı olarak standart haline geldiğinde isteğe bağlı bir döndürme)
einpoklum

@einpoklum Sabit doğruluk noktası çoğunlukla statik derleme zamanı denetimidir. Const nesnelerini doğru kullanmadığım için bir istisna atmak yerine derleyicinin şikayet etmesini tercih ederim.
Millie Smith

@einpoklum Çok geç, ancak diğer okuyucular için: bu kadar farklı şeyler yapan iki aşırı yüklemeye sahip olmak korkunç olurdu. Bunun atiki çeşidi olmasının tek nedeni , a yapmasıdır return *this;ve aşırı yükler arasındaki tek fark, constdöndürülen referansın -nessidir. Her ikisinin de gerçek etkileri attamamen aynıdır (yani, etkisi yoktur).
HTNW

28

Yeni okuyucular için not.
Asıl soru STL kapsayıcıları hakkındaydı (özellikle std :: map hakkında değil)

Çoğu kapsayıcıda [] operatörünün bir const sürümü olduğuna dikkat edilmelidir.
Sadece std :: map ve std :: set'in bir const sürümü olmadığı ve bu onları uygulayan temel yapının bir sonucudur.

Std :: vektör

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

Ayrıca ikinci örneğiniz için, elementi bulmakta başarısızlık olup olmadığını kontrol etmelisiniz.

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

1
std::sethiç yok operator[].
Herkes

2

[] Operatörü konteynere yeni bir öğe ekleyebileceğinden, muhtemelen bir const üye işlevi olamaz. [] Operatörünün tanımının son derece basit olduğuna dikkat edin: m [k], (* ((m.insert (değer_türü (k, veri_türü ())). Birinci)) ile eşdeğerdir. Kesinlikle, bu üye işlevi gereksizdir: sadece kolaylık sağlamak için vardır


0

Bir dizin operatörü yalnızca salt okunur bir kapsayıcı için const olmalıdır (aslında STL'de gerçekten mevcut değildir).

Dizin operatörleri yalnızca değerlere bakmak için kullanılmaz.


6
Soru şu ki, neden iki aşırı yüklenmiş versiyonu yok - biri const, diğeri olmayan const- örneğin olduğu std::vectorgibi.
Pavel Minaev

-2

Std :: map üye değişkeninizin değiştirilebilir olduğunu bildirirseniz

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

std :: map'in const olmayan üye işlevlerini const üye işlevleriniz içinde kullanabilirsiniz.


15
Yine de bu korkunç bir fikir.
GManNickG

7
Bunu yaparsanız sınıfınızın API'si yalan söyler. İşlev const olduğunu iddia eder - yani herhangi bir üye değişkeni değiştirmeyecektir - ancak gerçekte m_map veri üyesini değiştiriyor olabilir.
Runcible

2
mutablestd::mutexönbellek ve hata ayıklama yardımcıları gibi üyeler için kullanılabilir . Harita, çok pahalı bir const"alıcı" işlevini hızlandırmak için bir önbellek olarak kullanılacaksa , bu mutabledurumda kabul edilebilir. Dikkatli olmalısın, ama tek başına korkunç bir fikir değil.
Mark Lakata
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.