เหตุใดโอเปอเรเตอร์ [] จึงไม่เป็นค่าคงที่สำหรับแผนที่ STL


90

ตัวอย่างที่เขียนขึ้นเพื่อประโยชน์ของคำถาม:

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

สิ่งนี้จะไม่คอมไพล์เนื่องจาก [] ตัวดำเนินการไม่ใช่ const

นี่เป็นเรื่องที่น่าเสียดายเนื่องจากไวยากรณ์ [] ดูสะอาดมาก แต่ฉันต้องทำสิ่งนี้แทน:

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

สิ่งนี้ทำให้ฉันรู้สึกแย่เสมอ เหตุใดตัวดำเนินการ [] จึงไม่ใช่ const


5
สิ่งที่ควรoperator[]ให้ผลในกรณีที่ไม่มีองค์ประกอบที่กำหนด?
Frerich Raabe

5
@Frerich Raabe: สิ่งเดียวกับฟังก์ชัน at member: throw std :: out_of_range
Jean-Simon Brochu

คำตอบ:


91

สำหรับstd::mapและstd::unordered_map, operator[]จะแทรกค่าดัชนีลงในภาชนะถ้ามันไม่ได้อยู่ก่อนหน้านี้ มันไม่ได้ใช้งานง่ายเล็กน้อย แต่ก็เป็นอย่างนั้น

เนื่องจากต้องได้รับอนุญาตให้ล้มเหลวและใส่ค่าเริ่มต้นจึงไม่สามารถใช้ตัวดำเนินการกับconstอินสแตนซ์ของคอนเทนเนอร์ได้

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


3
std::setoperator[]ไม่ได้มี
avakar

2
นั่นเป็นคำตอบที่ถูกต้อง แต่เวอร์ชัน const สามารถทำสิ่งเดียวกันกับสมาชิก "at" ได้ นั่นคือการขว้าง std :: out_of_range ...
Jean-Simon Brochu

เมื่อใช้เพื่ออ่านค่าจะไม่มีค่าเริ่มต้นที่จะระบุ std::vectorมีผู้ประกอบการอ่านที่เป็น[] ควรทำเช่นเดียวกัน constmap
wcochran

52

ตอนนี้ด้วย C ++ 11 คุณสามารถมีเวอร์ชันที่สะอาดกว่าได้โดยใช้ที่ ()

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

4
หากmapมี const และ non-const at()- ทำไมไม่เหมือนกันสำหรับoperator[]? ด้วยเวอร์ชัน const ไม่ได้ใส่อะไรเลย แต่เป็นการขว้างปา? (หรือส่งคืนตัวเลือกเมื่อ std :: optional ทำให้เข้าสู่มาตรฐาน)
einpoklum

@einpoklum จุดของความถูกต้องของ const ส่วนใหญ่เป็นการตรวจสอบเวลาคอมไพล์แบบคงที่ ฉันอยากให้คอมไพเลอร์บ่นมากกว่าโยนข้อยกเว้นเพราะฉันไม่ได้ใช้วัตถุ const อย่างถูกต้อง
Millie Smith

@einpoklum สายมาก แต่สำหรับผู้อ่านคนอื่น ๆ การมีงานหนักเกินไปสองครั้งในการทำสิ่งที่แตกต่างกันนั้นจะแย่ เหตุผลเดียวที่atมาในสองรสชาติเป็นเพราะมันทำ a return *this;และความแตกต่างเพียงอย่างเดียวระหว่างการโอเวอร์โหลดคือความconst-ness ของการอ้างอิงที่ส่งคืน ผลกระทบที่แท้จริงของทั้งสองatเหมือนกันทุกประการ (นั่นคือไม่มีผลกระทบ)
HTNW

28

หมายเหตุสำหรับผู้อ่านใหม่
คำถามเดิมเกี่ยวกับคอนเทนเนอร์ STL (ไม่เฉพาะเกี่ยวกับ std :: map)

ควรสังเกตว่ามีตัวดำเนินการเวอร์ชัน const [] ในคอนเทนเนอร์ส่วนใหญ่
เป็นเพียงแค่ว่า std :: map และ std :: set ไม่มีเวอร์ชัน const และนี่เป็นผลมาจากโครงสร้างพื้นฐานที่นำมาใช้

จาก std :: vector

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

นอกจากนี้สำหรับตัวอย่างที่สองของคุณคุณควรตรวจสอบความล้มเหลวในการค้นหาองค์ประกอบ

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::setไม่ได้มีoperator[]ที่ทั้งหมด
ทุกคน

2

เนื่องจากตัวดำเนินการ [] อาจแทรกองค์ประกอบใหม่ลงในคอนเทนเนอร์จึงไม่สามารถเป็นฟังก์ชันสมาชิก const ได้ โปรดทราบว่าคำจำกัดความของตัวดำเนินการ [] นั้นง่ายมาก: m [k] เทียบเท่ากับ (* ((m.insert (value_type (k, data_type ())))). วินาที พูดอย่างเคร่งครัดฟังก์ชั่นสมาชิกนี้ไม่จำเป็น: มีไว้เพื่อความสะดวกเท่านั้น


0

ตัวดำเนินการดัชนีควรเป็น const สำหรับคอนเทนเนอร์แบบอ่านอย่างเดียวเท่านั้น (ซึ่งไม่มีอยู่จริงใน STL per se)

ตัวดำเนินการดัชนีไม่ได้ใช้เพื่อดูค่าเท่านั้น


6
คำถามก็คือว่าทำไมไม่ได้มีสองรุ่นมากเกินไป - เป็นหนึ่งในconstอีกไม่const- เป็นเช่นstd::vectorใด
Pavel Minaev

-2

หากคุณประกาศตัวแปรสมาชิก std :: map ของคุณให้เปลี่ยนแปลงได้

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

คุณสามารถใช้ฟังก์ชันสมาชิกที่ไม่ใช่ const ของ std :: map ภายในฟังก์ชันสมาชิก const ของคุณ


15
นี่เป็นความคิดที่แย่มาก
GManNickG

7
API สำหรับชั้นเรียนของคุณอยู่หากคุณทำเช่นนั้น ฟังก์ชั่นอ้างว่าเป็น const ซึ่งหมายความว่าจะไม่แก้ไขตัวแปรสมาชิกใด ๆ - แต่ในความเป็นจริงมันอาจจะแก้ไขสมาชิกข้อมูล m_map
Runcible

2
mutableสามารถใช้สำหรับสมาชิกเช่นstd::mutexแคชและตัวช่วยแก้ไขข้อบกพร่อง หากแผนที่จะใช้เป็นแคชเพื่อเร่งความเร็วconstฟังก์ชัน "getter" ที่มีราคาแพงมากก็mutableเป็นที่ยอมรับได้ คุณต้องระวัง แต่มันไม่ใช่ความคิดที่น่ากลัวในตัวเอง
Mark Lakata
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.