C ++ STL Vectors : 인덱스에서 반복자를 가져 옵니까?


200

따라서 index []로 stl 벡터의 요소에 액세스하는 많은 코드를 작성했지만 이제는 벡터 덩어리 만 복사해야합니다. 것 같습니다 vector.insert(pos, first, last)난 단지 제의 int로서 마지막이 제외 ... 내가 원하는 기능입니다. 이 값에 대한 반복자를 얻을 수있는 좋은 방법이 있습니까?



내가 틀리지 않으면 어떤 대답도 경계 검사를 수행하지 않으므로 문제가 될 수 있습니다. 특히 std :: advance docs는 기본 컨테이너 경계를 벗어나기 위해 동작을 사용하면 동작이 정의되지 않았다고 말합니다.
Martin Pecka

답변:


293

이 시도:

vector<Type>::iterator nth = v.begin() + index;

4
일반적으로 포인터와 STL 반복자를 사용하여 동일한 산술을 사용할 수 있습니다. STL 알고리즘을 사용할 때 교환 할 수 있도록 설계되었습니다.
Vincent Robert

18
@ VincentRobert : 다른 방법. 포인터는 가장 강력한 범주 인 STL 랜덤 반복기의 유효한 구현입니다. 그러나 순방향 반복자와 같은 덜 강력한 범주는 동일한 산술을 지원하지 않습니다.
MSalters

6
이 답변에 5 센트를 추가하고 추천하고 싶습니다std::next(v.begin(), index)
stryku

87

@dirkgently에 의해 언급 된 방법 ( v.begin() + index )은 벡터 에 좋고 훌륭합니다.

그러나 가장 일반적인 방법과 무작위 액세스 반복자도 일정한 시간 동안 작동합니다. std::advance( v.begin(), index )


사용법의 차이점 편집 :

std::vector<>::iterator it = ( v.begin() + index );

또는

std::vector<>::iterator it = v.begin();
std::advance( it, index );

@litb 메모 뒤에 추가되었습니다.


std :: advance가 첫 번째 인수로 비 const 반복자를 필요로하지 않습니까?
goldPseudo

const와 non-const 반복자와 함께 std :: advance를 사용할 수 있습니다
bayda

1
그런 점에서 msvc를 신뢰해서는 안됩니다. 그것은 비표준 확장을 가지고있어서 이런 종류의 것을 받아들이지 만 다른 모든 컴파일러는 표준으로 행동하고 거부합니다.
Johannes Schaub-litb

1
문제는 "const"의 의미를 혼동한다고 생각합니다. advance ()는 const_iterator <T>에서 행복하게 작동합니다. const_iterator <T>는 유형 T의 const 요소를 참조하는 변경 가능한 반복자입니다. 그 자체가 const 인 반복자 객체 (예 : "const iterator <T>"또는 "iterator <T> const")에서는 작동하지 않습니다.
j_random_hacker

7
을 다루는 것을 알고 있다면 을 사용할 필요가 std::vector없습니다 std::advance. 컨테이너에 구애받지 않는 코드를 작성한다고 생각할뿐입니다 (반복하지 않는 반복자 무효화 규칙, 다른 런타임 복잡성 등). 이해하는 유일한 경우 std::advance는 템플릿을 직접 작성하여 처리하는 반복자 유형을 모르는 경우입니다.
Frerich Raabe

47

또한; auto it = std::next(v.begin(), index);

업데이트 : C ++ 11x 호환 컴파일러 필요


2
이것이 C ++ 11 방식이라는 점에 유의해야합니다! std :: next는 std :: advance와 같습니다. 산술을 사용하는 대신 이러한 함수를 사용하면 컨테이너 유형을 훨씬 쉽게 교체 할 수 있습니다. std :: begin 및 std :: end와 같이 c-arrays afaik에서도 작동합니다.
Zoomulator

2
std :: advance는 반환 값이 아닌 출력으로 참조를 사용하기 때문에 바보에 의해 설계되었습니다.
Viktor Sehr

1
for (auto it = begin (c); it! = end (c); advance (it, n)) {...}
Zoomulator

2
둘 다 용도가 있습니다. stda :: advance는 반복자를 제자리에 변경하는 데 유용합니다. 루프의 성능 문제입니다. 당신이 제안한대로 과제의 경우 다음을 선호합니다. 방금 바보라고 주장하는 것이 조금 거칠 었습니다. 두 기능은 기본적으로 동일하더라도 서로 다른 상황을 염두에두고 설계되었습니다.
Zoomulator

5
@Zoomulator : 반복자를 복사하는 것이 성능 문제인 경우 처리해야 할 더 큰 문제가 있습니다.
Mooing Duck

8

아니면 사용할 수 있습니다 std::advance

vector<int>::iterator i = L.begin();
advance(i, 2);

-3

실제로 std :: vector는 필요할 때 C 탭으로 사용됩니다. (C ++ 표준 은 Wikipedia에서 배열을 대체하는 것으로 알고있는 한 벡터 구현을 요구합니다. ) 예를 들어,이 folowing을 수행하는 것은 완벽하게 합법적입니다.

int main()
{

void foo(const char *);

sdt::vector<char> vec;
vec.push_back('h');
vec.push_back('e');
vec.push_back('l');
vec.push_back('l');
vec.push_back('o');
vec.push_back('/0');

foo(&vec[0]);
}

물론, foo는 매개 변수로 전달 된 주소를 복사하여 어딘가에 저장하지 않아야합니다. 또는 프로그램에서 vec에 새 항목을 넣지 않거나 용량 변경을 요청하지 않아야합니다. 또는 위험 세분화 오류 ...

따라서 당신의 예에서 그것은

vector.insert(pos, &vec[first_index], &vec[last_index]);

그들이 단지 포인터라면 반복자들에게 추상화하기로 결정한 이유를 궁금하게 만듭니다.
mpen

편의를 위해? 코드에서 다른 종류의 컨테이너에 대한 벡터 인스턴스를 쉽게 제거 할 수 있습니다.
yves Baumes

4
& vec [i]는 vector <> :: iterator와 반드시 호환되지 않는 포인터를 생성합니다. vec.begin () + i는 여전히 디버그 모드에서 확인 된 반복자를 포함하여 라이브러리가 정의한 반복자가 무엇이든 이점이 있습니다. 따라서 포인터가 필요하지 않은 경우 (예 : I / O의 경우) 항상 반복자를 선호해야합니다.
sellibitze

@KerrekSB c ++ 표준 초안의 23.3.6.1부터 : "벡터의 요소는 연속적으로 저장됩니다. 즉, v가 vector <T, Allocator> 인 경우 T는 bool이 아닌 다른 유형 인 경우 & v [ n] == & v [0] + n 모두 0 <= n <v.size () "
yves Baumes

2
@yvesBaumes : 벡터 반복자와는 아무런 관련이 없습니다. 그러나, 알몸 포인터 것은 사실 이다 또한 반복자 - 그들은 단지 아니에요 벡터 반복자.
Kerrek SB
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.