STL 맵에 대해 [] 연산자가 const가 아닌 이유는 무엇입니까?


89

질문에 대한 설명 된 예 :

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

[] 연산자가 상수가 아니기 때문에 컴파일되지 않습니다.

[] 구문이 매우 깔끔해 보이기 때문에 이것은 불행한 일입니다. 대신 다음과 같이해야합니다.

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

이것은 항상 나를 괴롭 혔습니다. [] 연산자가 상수가 아닌 이유는 무엇입니까?


5
operator[]주어진 요소가 존재하지 않는 경우 무엇을 산출 해야 합니까?
Frerich Raabe

4
@Frerich 라베 : 멤버 함수에서 같은 일 : 던져 표준 : : out_of_range
장 - 사이먼 브로 슈

답변:


90

들어 std::mapstd::unordered_map, operator[]이전에 존재하지 않은 경우 용기에 인덱스 값을 삽입합니다. 약간 직관적이지 않지만 그렇습니다.

실패하고 기본값을 삽입 할 수 있어야하므로 const컨테이너 의 인스턴스 에서 연산자를 사용할 수 없습니다 .

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


3
std::set이 없습니다 operator[].
avakar

2
정답이지만 const 버전은 "at"멤버와 동일한 작업을 수행 할 수 있습니다. 그건 표준 : : out_of_range을 던져 ...
장 - 사이먼 브로 슈

값을 읽는 데 사용되는 경우 제공 할 기본값이 없습니다. std::vector인 읽기 연산자 []const있습니다. map똑같이해야합니다.
wcochran

51

이제 C ++ 11 에서는 at () 을 사용하여 더 깨끗한 버전을 가질 수 있습니다.

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

4
mapconst 및 non-const at()s 가 있으면 왜 동일하지 operator[]않습니까? const 버전은 아무것도 삽입하지 않고 던지는? (또는 선택 사양을 반환 할 때 표준에 표준 : 옵션 차종을)
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

operator []는 컨테이너에 새 요소를 삽입 할 수 있으므로 const 멤버 함수가 될 수 없습니다. operator []의 정의는 매우 간단합니다. m [k]는 (* ((m.insert (value_type (k, data_type ()))). first)). second와 같습니다. 엄밀히 말하면이 멤버 함수는 불필요합니다. 편의를 위해서만 존재합니다.


0

인덱스 연산자는 읽기 전용 컨테이너 (STL 자체에는 실제로 존재하지 않음)에 대해서만 const 여야합니다.

인덱스 연산자는 값을 보는 데만 사용되는 것이 아닙니다.


6
한 - 그것은 두 개의 오버로드 된 버전이없는 이유를 질문은, const다른 비 const- 예를 들면 같이 std::vector한다.
Pavel Minaev

-2

std :: map 멤버 변수를 변경 가능하도록 선언하면

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

const 멤버 함수 내에서 std :: map의 상수가 아닌 멤버 함수를 사용할 수 있습니다.


15
하지만 이것은 끔찍한 생각입니다.
GManNickG

7
당신이 그렇게한다면 당신의 클래스를위한 API는 거짓말입니다. 이 함수는 const라고 주장합니다. 즉, 멤버 변수를 수정하지 않는다는 의미이지만 실제로는 m_map 데이터 멤버를 수정할 수 있습니다.
Runcible

2
mutablestd::mutex, 캐시 및 디버그 도우미와 같은 멤버에 사용할 수 있습니다 . 맵이 매우 값 비싼 const"getter"기능의 속도를 높이기 위해 캐시로 사용되는 경우 mutable허용됩니다. 조심해야하지만 그 자체로는 끔찍한 생각이 아닙니다.
Mark Lakata 2015 년
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.