왜 std :: string :: find ()가 실패했을 때 end iterator를 반환하지 않습니까?


29

std::string::find표준 C ++ 컨테이너와 동작 이 일치하지 않습니다.

예 :

std::map<int, int> myMap = {{1, 2}};
auto it = myMap.find(10);  // it == myMap.end()

그러나 문자열의 경우

std::string myStr = "hello";
auto it = myStr.find('!');  // it == std::string::npos

왜 실패한 myStr.find('!')반품 myStr.end()std::string::npos아닌가?

std::string다른 컨테이너와 비교할 때 다소 특별 하기 때문에 이것 뒤에 진짜 이유가 있는지 궁금합니다. (놀랍게도, 나는 이것을 어디에서나 질문하는 사람을 찾을 수 없었다).


5
나는 합리적인 대답 만이 질문에 대한 대답에 가깝다고 생각합니다. 글쎄, 그것은 세상이
일어난


IMHO,이 동작의 이유는 std::string내부적으로 저렴한 요소 (메모리와 관련하여) 인 문자로 구성 되기 때문 입니다. 또한 캐릭터는 std::string포함 할 수있는 유일한 유형 입니다. 반면 std::map에 더 복잡한 요소로 구성됩니다. 또한 사양은 std::map::find요소를 찾는 것으로되어 있으며 사양은 std::string::find위치를 찾는 것입니다.
NutCracker

맵의 경우 npos 반복자를 가질 수 없으므로 종료 반복기가 사용됩니다. 문자열의 경우 npos를 사용할 수 있습니다. 왜 그렇지 않을까요 :)
LF

답변:


28

우선, std::string인터페이스가 부풀어지고 일관성이없는 것으로 잘 알려져 있습니다 .이 주제에 대한 Herb Sutter의 Gotw84 를 참조하십시오 . 그럼에도 불구하고 std::string::find인덱스를 반환하는 이유는 다음과 같습니다 std::string::substr. 이 편리한 멤버 함수는 인덱스에서 작동합니다. 예 :

const std::string src = "abcdefghijk";

std::cout << src.substr(2, 5) << "\n";

substr반복자를 문자열로 받아들이도록 구현할 수는 있지만 std::string사용할 수없고 반 직관적 인 큰 불만을 기다릴 필요 는 없습니다. 따라서 std::string::substr인덱스 를 받아들이면 'd'이 하위 문자열에서 시작하는 모든 것을 인쇄하기 위해 위의 입력 문자열에서 처음 나타나는 인덱스를 어떻게 찾을 수 있습니까?

const auto it = src.find('d'); // imagine this returns an iterator

std::cout << src.substr(std::distance(src.cbegin(), it));

이것은 또한 당신이 원하는 것이 아닐 수도 있습니다. 따라서 우리 std::string::find는 색인을 반환하도록 할 수 있으며 여기에 있습니다 :

const std::string extracted = src.substr(src.find('d'));

이터레이터로 작업하려면을 사용하십시오 <algorithm>. 그들은 당신을 위와 같이 허용합니다

auto it = std::find(src.cbegin(), src.cend(), 'd');

std::copy(it, src.cend(), std::ostream_iterator<char>(std::cout));

4
좋은 지적. 그러나 대신에 반복자를 반환하는 std::string::find여전히 반환 할 수 size(), 대신 npos과의 호환성을 유지, substr또한 몇 가지 추가 된 brances을 피하면서.
erenon

1
@erenon 아마도 std::string::substr두 번째 인덱스 ( npos)에 대한 기본 매개 변수를 사용하여 "끝까지 시작"사례를 이미 다룹니다 . 돌아 오는 size()것도 혼란스럽고 문자 그대로의 센티넬을 갖는 npos것이 더 나은 선택일까요?!
lubgr

@lubgr 그러나 std::string::find반복자를 반환 std::string::substr하면 시작 위치에 대한 반복자를 허용 할 수도 있습니다. 이 대체 세계에서 두 경우 모두 find를 사용한 예제는 동일하게 보입니다.
Mattias Wallin

@MattiasWallin 좋은 지적입니다. 그러나 std::string::substr반복자 인수를 사용하면 추가 UB 사례 (지수 또는 반복자에서 똑같이 발생할 수있는 과거 시나리오 제외) : 다른 문자열을 참조하는 반복자를 전달할 수 있습니다.
lubgr

3

std::string두 가지 인터페이스 가 있기 때문입니다 .

  • 모든 컨테이너에서 발견 되는 일반 반복자 기반 인터페이스
  • std::string특정의 인덱스 기반의 인터페이스

std::string::find인덱스 기반 인터페이스의 일부 이므로 인덱스를 반환합니다.

사용하여 std::find일반 반복자 기반 인터페이스를 사용 할 수 있습니다.

std::vector<char>인덱스 기반 인터페이스를 원하지 않는 경우 사용하십시오 (이 작업을 수행하지 마십시오).

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.