การเข้าถึงแผนที่ C ++ ละทิ้งคุณสมบัติ (const)


113

รหัสต่อไปนี้ระบุว่าการส่งผ่านแผนที่constใน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;
}

นี่เป็นเพราะการจัดสรรที่เป็นไปได้ที่เกิดขึ้นในการเข้าถึงแผนที่หรือไม่? ไม่สามารถประกาศฟังก์ชันที่มีการเข้าถึงแผนที่ได้หรือไม่

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


เพียงแค่ nitpick แต่ mw สามารถประกาศได้ง่ายๆว่า MapWrapper mw;
luke

จุดดี - ฉันเขียนเป็นสองสามภาษาดังนั้นฉันจึงมักจะทำให้ไวยากรณ์เป็นปกติเพื่อให้พวกเขาทั้งหมดพอดีกับหัวของฉัน :)
cdleary

ฉันสามารถขอบคุณที่ โปรดระวังในกรณีเช่นนี้คุณจะมีโครงสร้างและการมอบหมายวัตถุพิเศษที่ไม่จำเป็น
luke

จุดดีอีกประการหนึ่ง - การอาศัยตัวดำเนินการกำหนดค่าเริ่มต้นไม่ใช่แนวทางปฏิบัติที่ดีสำหรับตัวอย่างสาธารณะ ;)
cdleary

คำตอบ:


152

std::map's operator []ไม่ได้ประกาศให้เป็นconstและไม่สามารถจะเป็นเพราะพฤติกรรมของมัน:

T & operator [] (const Key & key)

ส่งคืนการอ้างอิงถึงค่าที่แมปกับคีย์ที่เทียบเท่ากับคีย์โดยทำการแทรกหากคีย์ดังกล่าวไม่มีอยู่

ด้วยเหตุนี้จึงไม่สามารถประกาศฟังก์ชันของคุณconstและใช้แผนที่operator[]ได้

std::mapของfind()ฟังก์ชั่นช่วยให้คุณมองขึ้นไปที่สำคัญโดยไม่ต้องแก้ไขแผนที่

find()ส่งคืนค่าiteratorหรือconst_iteratorเป็นค่าstd::pairที่มีทั้งคีย์ ( .first) และค่า ( .second)

ใน C ++ 11 คุณสามารถใช้at()สำหรับstd::map. หากองค์ประกอบไม่ได้อยู่ฟังก์ชั่นพ่นยกเว้นในทางตรงกันข้ามกับstd::out_of_rangeoperator []


8
นอกจากนี้: VALUE = map.find (KEY) -> วินาที; ฉันต้องเรียนรู้ว่า 'find ()' ส่งคืนตัวทำซ้ำซึ่งเป็นประเภทคู่
FlipMcF

5
ฉันจะเพิ่มว่าตอนนี้ใน C11 คุณสามารถใช้: std :: map :: at (key) และหลีกเลี่ยงตัววนซ้ำ
Juan Besa

3
น่าสนใจ ฉันคิดว่า C ++ จะแยกความแตกต่างระหว่าง lvalue operator[](เช่นfoo[bar] = baz) และ rvalue operator[](เช่นx = foo[bar]) - ตัวหลังอาจเป็น const อย่างแน่นอน
Claudiu

15

เนื่องจากoperator[]ไม่มีการโอเวอร์โหลดที่ผ่านคุณสมบัติ const จึงไม่สามารถใช้อย่างปลอดภัยในฟังก์ชันที่มีคุณสมบัติเหมาะสม อาจเป็นเพราะการโอเวอร์โหลดปัจจุบันถูกสร้างขึ้นโดยมีเป้าหมายในการส่งคืนและตั้งค่าคีย์

คุณสามารถใช้:

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

หรือใน C ++ 11 คุณสามารถใช้ตัวat()ดำเนินการ:

VALUE = map.at(KEY);

map.find(KEY)->second; ไม่ปลอดภัยเมื่อค่าแผนที่เป็นสตริง มีแนวโน้มที่จะพิมพ์ขยะเมื่อไม่พบ KEY
syam

1
นั่นเป็นคำตอบที่อธิบายได้อย่างถูกต้องซึ่งตรงประเด็น เมื่อวานนี้ฉันใช้เวลา 2 ชั่วโมงในการพยายามคิดว่าเกิดอะไรขึ้นกับกรณีที่คล้ายกัน เรายอมรับได้หรือไม่ว่าข้อความแสดงข้อผิดพลาดที่ดีที่สุดทำให้เข้าใจผิด ฉันอาจจะเป็นวิธีการที่ชัดเจนมากขึ้นถ้ามันไม่ได้มีคำว่า 'นี้' และได้อ้างอิงถึงconst-Nessแทนทั่วไปมากขึ้นรอบคัดเลือก
carnicer

11

คุณไม่สามารถใช้operator[]บนแผนที่ที่เป็นไปconstตามวิธีการนั้นไม่ได้constเนื่องจากอนุญาตให้คุณแก้ไขแผนที่ได้ (คุณสามารถกำหนดให้_map[key]) ลองใช้findวิธีแทน


1
ตามคำอธิบาย: ตัวดำเนินการของแผนที่ [] ควรทำอย่างไรหากไม่มีคีย์ หากแผนที่ไม่ใช่ const คีย์จะถูกเพิ่มด้วยค่าที่สร้างขึ้นเริ่มต้น ถ้าแผนที่ const สิ่งที่สามารถส่งคืนโดย operator []? ไม่มีค่าที่คีย์นั้น

นั่นเป็นคำตอบที่อธิบายได้อย่างถูกต้องซึ่งตรงประเด็น เมื่อวานนี้ฉันใช้เวลา 2 ชั่วโมงในการพยายามคิดว่าเกิดอะไรขึ้นกับกรณีที่คล้ายกัน เรายอมรับได้หรือไม่ว่าข้อความแสดงข้อผิดพลาดที่ดีที่สุดทำให้เข้าใจผิด ฉันอาจจะเป็นวิธีการที่ชัดเจนมากขึ้นถ้ามันไม่ได้มีคำว่า 'นี้' และได้อ้างอิงถึงconst-Nessแทนทั่วไปมากขึ้นรอบคัดเลือก
carnicer

7

ส่วนหัว GCC เวอร์ชันใหม่กว่า (4.1 และ 4.2 บนเครื่องของฉัน) มีฟังก์ชันสมาชิกที่ไม่ได้มาตรฐานแมป :: at () ซึ่งประกาศ const และโยน std :: out_of_range หากคีย์ไม่อยู่ในแผนที่

const mapped_type& at(const key_type& __k) const

จากการอ้างอิงในข้อคิดเห็นของฟังก์ชันปรากฏว่าสิ่งนี้ได้รับการแนะนำให้เป็นฟังก์ชันสมาชิกใหม่ในไลบรารีมาตรฐาน


ฉันเดาว่าเป็นเรื่องแปลก ๆ at-function เป็นส่วนหนึ่งของมาตรฐานที่กำลังจะมาถึง แต่ฉันไม่พบที่ () ในมาตรฐานปัจจุบัน
Sebastian Mach

'at' เป็นส่วนหนึ่งของ C ++ 11
Étienne

0

ขั้นแรกคุณไม่ควรใช้สัญลักษณ์ที่ขึ้นต้นด้วย _ เพราะสงวนไว้สำหรับการใช้งานภาษา / ตัวเขียนคอมไพเลอร์ มันจะง่ายมากที่ _map จะเป็นข้อผิดพลาดทางไวยากรณ์ในคอมไพเลอร์ของใครบางคนและคุณจะไม่มีใครตำหนินอกจากตัวคุณเอง

หากคุณต้องการใช้ขีดล่างให้ใส่ไว้ที่ส่วนท้ายไม่ใช่จุดเริ่มต้น คุณอาจทำผิดพลาดนี้เนื่องจากคุณเห็นรหัส Microsoft บางรหัสกำลังทำอยู่ จำไว้ว่าพวกเขาเขียนคอมไพเลอร์ของตัวเองดังนั้นพวกเขาอาจจะหนีไปได้ ถึงกระนั้นก็เป็นความคิดที่ไม่ดี

ตัวดำเนินการ [] ไม่เพียง แต่ส่งคืนข้อมูลอ้างอิงเท่านั้น แต่ยังสร้างรายการในแผนที่อีกด้วย ดังนั้นคุณไม่เพียงแค่ได้รับการทำแผนที่หากไม่มีคุณกำลังสร้างขึ้นมา นั่นไม่ใช่สิ่งที่คุณตั้งใจไว้


5
ประเด็นของคุณ_ไม่ถูกต้อง ตัวระบุที่ขึ้นต้นด้วยสองขีดล่าง ( __example) หรือตัวระบุที่ขึ้นต้นด้วยขีดล่างหนึ่งอันและตัวพิมพ์ใหญ่ ( _Example) สงวนไว้ _exampleไม่สงวนลิขสิทธิ์
Ethan
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.