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

맵 액세스에서 발생 가능한 할당 때문입니까? 맵 액세스가있는 함수를 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


그냥 간단하지만 mw는 MapWrapper mw로 간단히 선언 할 수 있습니다.
luke

좋은 점-저는 몇 가지 언어로 작성하기 때문에 구문을 정규화하는 경향이 있으므로 모두 내 머리에 맞습니다. :)
cdleary

감사합니다. 그러나 이와 같은 경우에는 필요하지 않은 추가 개체 구성 및 할당이 있으므로주의하십시오.
luke

또 다른 좋은 점은 기본 할당 연산자에 의존하는 것은 공개 예제에 적합하지 않다는 것입니다. ;)
cdleary

답변:


152

std::mapoperator []는로 선언 const되지 않았으며 동작으로 인해 발생할 수 없습니다.

T & 연산자 [] (상수 키 & 키)

키에 해당하는 키에 매핑 된 값에 대한 참조를 반환하여 해당 키가 아직없는 경우 삽입을 수행합니다.

결과적으로 함수를 선언 할 수 없으며 const지도의 operator[].

std::mapfind() 기능을 사용하면지도를 수정하지 않고도 키를 조회 할 수 있습니다.

find()를 반환 iterator하거나 const_iterator내지 An std::pair키 (모두 포함 .first) 및 값 ( .second).

C ++ 11에서는, 당신은 또한 사용할 수 있습니다 at()에 대한 std::map. 요소가 존재하지 않으면 함수는 std::out_of_range예외를 던집니다 operator [].


8
추가로 : VALUE = map.find (KEY)-> second; 나는 '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 한정된 오버로드가 없기 때문에 const 한정 함수에서 안전하게 사용할 수 없습니다. 이는 현재 과부하가 키 값을 반환하고 설정하는 목표로 구축 되었기 때문일 수 있습니다.

대신 다음을 사용할 수 있습니다.

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

또는 C ++ 11에서는 at()연산자를 사용할 수 있습니다 .

VALUE = map.at(KEY);

map.find(KEY)->second; 맵 값이 문자열이면 안전하지 않습니다. KEY를 찾을 수 없을 때 쓰레기를 인쇄하는 경향이 있습니다.
syam

1
그것은 요점으로 이동하는 적절하게 설명 된 대답입니다. 어제 나는 비슷한 사건에서 무슨 일이 일어나고 있는지 알아 내기 위해 2 시간을 보냈다. 오류 메시지가 기껏해야 오해의 소지가 있다는 데 동의 할 수 있습니까? 'this'라는 단어가없고 더 일반적인 한정자 대신 const-ness 를 참조하면 더 명확해질 수 있습니다. .
carnicer

11

사용할 수 없습니다 operator[]지도 를 수정할 수 const있는 방법이 아니므 const로 지도 (에 할당 할 수 있음 _map[key]). find대신 방법을 사용해보십시오 .


1
설명 : 키가 존재하지 않으면 map의 operator []는 무엇을해야합니까? 지도가 상수가 아니면 키가 기본 생성 값으로 추가됩니다. 지도가 const이면 operator []가 무엇을 반환 할 수 있습니까? 그 키에는 가치가 없습니다.

그것은 요점으로 이동하는 적절하게 설명 된 대답입니다. 어제 나는 비슷한 사건에서 무슨 일이 일어나고 있는지 알아 내기 위해 2 시간을 보냈다. 오류 메시지가 기껏해야 오해의 소지가 있다는 데 동의 할 수 있습니까? 'this'라는 단어가없고 보다 일반적인 한정자 대신에 const-ness 를 참조하면 더 명확해질 수 있습니다 .
carnicer

7

일부 최신 버전의 GCC 헤더 (내 컴퓨터의 4.1 및 4.2)에는 const로 선언 된 비표준 멤버 함수 map :: at ()이 있으며 키가 맵에 없으면 std :: out_of_range를 throw합니다.

const mapped_type& at(const key_type& __k) const

함수 주석의 참조에서 이것이 표준 라이브러리의 새 멤버 함수로 제안 된 것으로 보입니다.


약간 특이한 것 같아요. at- 함수는 다가오는 표준의 일부이지만 현재 표준에는 at ()이 없습니다.
Sebastian Mach

'at'는 C ++ 11의 일부입니다.
Étienne 2014 년

0

첫째, _로 시작하는 기호는 언어 구현 / 컴파일러 작성기에 예약되어 있으므로 사용하지 않아야합니다. _map이 다른 사람의 컴파일러에서 구문 오류가되는 것은 매우 쉬울 것이며, 당신은 자신을 비난 할 사람이 없을 것입니다.

밑줄을 사용하려면 시작 부분이 아니라 끝 부분에 넣으십시오. Microsoft 코드에서이 작업을 수행하는 것을 보았 기 때문에이 실수를했을 것입니다. 기억하세요, 그들은 그들 자신의 컴파일러를 작성하기 때문에 그것을 피할 수 있습니다. 그럼에도 불구하고 그것은 나쁜 생각입니다.

연산자 []는 참조를 반환 할뿐만 아니라 실제로 맵에 항목을 생성합니다. 따라서 매핑을 얻는 것이 아니라 매핑이 없으면 새로 만드는 것입니다. 그것은 당신이 의도 한 것이 아닙니다.


5
귀하의 요점 _이 잘못되었습니다. 두 개의 밑줄 ( __example)로 시작하는 식별자 또는 하나의 밑줄과 대문자 ( _Example)로 시작하는 식별자 는 예약되어 있습니다. _example예약되지 않았습니다.
Ethan
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.