C++ iterator는 temporary object인가요?

BOJ에서 문제를 풀다 std::map을 사용할 일이 생겼습니다.
map에 어떤 Key가 있는지 조회하기 위해 find를 사용했는데요,
참조로 받으면 복사보다 효율적이지 않을까하는 생각에

unordered_map<string, int>::iterator& it = name_map.find(name1);

이렇게 선언했는데 컴파일 오류가 발생하더라구요.
이유가 뭘까 구글을 열심히 뒤져봤는데, 이렇다 할 이유를 못 찾았습니다… :sob:
std::vector::begin()이 임시 객체를 반환한다는 글을 보긴했는데,
이게 맞는 말인지, 또한 find()를 비롯한 iterator를 반환하는 모든 함수에도 적용가능한 말인지 모르겠어서 질문 드립니다.

(PS하던 문제 코드는 조금 지저분해서 혼자 테스팅하던 코드와 에러메시지를 대신 올립니다)

#include <iostream>
#include <unordered_map>
#include <string>
using namespace std;

int main()
{
    unordered_map<string, int> phone_book {
        {"David Hume", 123456},
        {"Karl Popper", 234567},
        {"Bertand Arthur", 345678}
    }; 

    // error: non-const lvalue reference to type '__hash_map_iterator<...>' cannot bind 
    // to a temporary of type '__hash_map_iterator<...>'
    unordered_map<string, int>::iterator& it = phone_book.find("David Hume");
    cout << it->first << " " << it->second;

    return 0;
}

더 헷갈리는 점은 const를 붙여서 선언하면 문제 없이 컴파일 및 실행이 된다는 점입니다.

#include <iostream>
#include <unordered_map>
#include <string>
using namespace std;

int main()
{
    unordered_map<string, int> phone_book {
        {"David Hume", 123456},
        {"Karl Popper", 234567},
        {"Bertand Arthur", 345678}
    }; 

    // add const type qualifier
    const unordered_map<string, int>::iterator& it = phone_book.find("David Hume");
    // OUTPUT: David Hume 123456
    cout << it->first << " " << it->second;

    return 0;
}

연휴가 끝나가는데 잘 마무리 하시고, 새해 복 많이 받으세요 :hugs:

https://en.cppreference.com/w/cpp/language/value_category

정확히는 저건 prvalue입니다

prvalue

  • a function call or an overloaded operator expression, whose return type is non-reference, such as str.substr(1, 2), str1 + str2, or it++;

rvalue

  • An rvalue expression is either prvalue or xvalue.
    An rvalue may be used to initialize a const lvalue reference, in which case the lifetime of the object identified by the rvalue is extended until the scope of the reference ends.

non-const lvalue reference를 초기화하는 우변값은 lvalue만 가능합니다

3 Likes

아하 말씀하신 부분이랑 레퍼런스를 봤더니 이해가 됩니다
std::cout << 1 ++it과 비교해보니 명확해지네요
prvalue인 iterator를 반환하는 것인데 lvalue reference가 가능할 것이라고 멋대로 판단한 것 같습니다 :disappointed_relieved:
답변 정말 감사드립니다 :hugs: