문제

다음 두 줄의 코드:

for (int i = 0; i < some_vector.size(); i++)
{
    //do stuff
}

이:

for (some_iterator = some_vector.begin(); some_iterator != some_vector.end();
    some_iterator++)
{
    //do stuff
}

말로는 두 번째 방법은 바람직하다.왜 정확히 이?

도움이 되었습니까?

해결책

첫 번째 형태는 vector.size ()가 빠른 작업 인 경우에만 효율적입니다. 예를 들어 벡터에는 적용되지만 목록에는 그렇지 않습니다. 또한 루프 본체 내에서 무엇을 할 계획입니까? 요소에 액세스 할 계획이라면

T elem = some_vector[i];

그런 다음 컨테이너가 가지고 있다고 가정하고 있습니다 operator[](std::size_t) 한정된. 다시 말하지만, 이것은 벡터에게는 해당되지만 다른 컨테이너에는 그렇지 않습니다.

반복자를 사용하면 컨테이너 독립성에 더 가깝습니다. 당신은 무작위 액세스 능력이나 빨리 가정하지 않습니다 size() 작동, 컨테이너에는 반복 기능이 있습니다.

표준 알고리즘을 사용하여 코드를 더욱 향상시킬 수 있습니다. 달성하려는 것이 무엇인지에 따라 사용하기로 선택할 수 있습니다. std::for_each(), std::transform() 등등. 명시 적 루프 대신 표준 알고리즘을 사용하면 휠을 다시 발명하는 것을 피할 수 있습니다. 코드가 더 효율적일 가능성이 높습니다 (올바른 알고리즘이 선택됨)는 정확하고 재사용 할 수 있습니다.

다른 팁

코드를 some_vector 목록의 특정 구현에 묶지 않기 때문입니다. 배열 인덱스를 사용하는 경우 어떤 형태의 배열이어야합니다. 반복자를 사용하는 경우 모든 목록 구현에서 해당 코드를 사용할 수 있습니다.

그것은 부분의 현대적인 C++교육 과정입니다.반복기는 유일한 방법으로 반복하는 대부분의 컨테이너,그래서 당신은 그것을 사용하도 벡터를 얻으로 적절한 사고 방식이다.심각하게는 이유로 내가 그 나는 생각하지 않는 이제까지를 대체하는 벡터와 다른 종류의 컨테이너입니다.


Wow,이것은 여전히 닫힌 영역 후습니다.나는 그것을 아무런 이익도 될 수 없는 백해무익한 작은 혀.

내가 생각하는 배열 색인이 더 많이 읽을 수 있습니다.과 일치하는 구문에서 사용되는 다른 언어로 사용되는 구문에 대한 옛날 C 배열입니다.그것은 또한 자세한 정보를 표시합니다.효율해야 세척하는 경우 컴파일러가 좋은,그리고 거의 모든 경우에요.

그럼에도 불구하고,나는 여전히 자신을 찾을 사용하여 반복기에 자주 비슷합니다.내가 믿고 반복자에 중요한 개념,그래서 나는 그것을 촉진하는 때마다 나는 할 수 있습니다.

일부 _vector가 링크리스트로 구현되었다고 상상해보십시오. 그런 다음 i 번째 장소에 항목을 요청하려면 노드 목록을 통과하기 위해 작업을 수행해야합니다. 이제 ITERATOR를 사용하는 경우 일반적으로 말하면 가능한 한 효율적으로 노력할 수 있도록 최선을 다할 것입니다 (링크 된 목록의 경우 현재 노드에 대한 포인터를 유지하고 각 반복에서 전진하여 단일 작동).

그래서 그것은 두 가지를 제공합니다.

  • 사용의 추상화 : 당신은 단지 몇 가지 요소를 반복하고 싶을 때, 당신은 그것을하는 방법에 신경 쓰지 않습니다.
  • 성능

나는 여기에서 악마 옹호자가 될 것이며 반복자를 추천하지 않을 것입니다. 주된 이유는 데스크탑 응용 프로그램 개발에서 게임 개발에 이르기까지 내가 작업 한 모든 소스 코드가 반복기를 사용해야했기 때문입니다. 항상 필요하지 않았으며 둘째, 숨겨진 가정과 코드 혼란과 반복자와 함께 얻는 악몽을 디버깅하면 속도가 필요한 어플리케이션에서 사용하지 않는 대표적인 예입니다.

고급 스탠드 포인트에서도 엉망입니다. 그것 때문에가 아니라 현장 뒤에서 발생하는 모든 별칭 때문입니다. 표준과 완전히 다른 것을 수행하는 자신의 가상 벡터 또는 배열 목록을 구현하지 않았다는 것을 어떻게 알 수 있습니까? 현재 런타임 중에 현재 어떤 유형이 있는지 알고 있습니까? 연산자에 과부하가 되었습니까? 모든 소스 코드를 확인할 시간이 없었습니다. 지옥에서 사용하는 STL 버전도 알고 있습니까?

반복자와 함께 얻은 다음 문제는 누출 추상화이지만,이를 자세히 논의하는 수많은 웹 사이트가 있습니다.

죄송합니다. 반복자의 지점을 보지 못했지만 아직 보지 못했습니다. 그들이 목록이나 벡터를 당신에게서 멀리 떨어 뜨린다면, 실제로 당신은 이미 어떤 벡터를 알고 있거나, 당신이하지 않으면, 당신이 앞으로 훌륭한 디버깅 세션을 위해 자신을 설정할 것입니다.

반복하는 동안 벡터에 항목을 추가/제거하려면 반복기를 사용하고 싶을 수도 있습니다.

some_iterator = some_vector.begin(); 
while (some_iterator != some_vector.end())
{
    if (/* some condition */)
    {
        some_iterator = some_vector.erase(some_iterator);
        // some_iterator now positioned at the element after the deleted element
    }
    else
    {
        if (/* some other condition */)
        {
            some_iterator = some_vector.insert(some_iterator, some_new_value);
            // some_iterator now positioned at new element
        }
        ++some_iterator;
    }
}

인덱스를 사용하는 경우 삽입 및 삭제를 처리하기 위해 배열에서 항목을 위/아래로 셔플해야합니다.

우려의 분리

반복 코드를 루프의 '핵심'문제와 분리하는 것이 매우 좋습니다. 거의 디자인 결정입니다.

실제로 인덱스에 의한 반복은 컨테이너의 구현에 연결됩니다. 컨테이너에 시작 및 엔드 반복기를 요청하면 루프 코드가 다른 컨테이너 유형에 사용할 수 있습니다.

또한 std::for_each 방법, 당신 묻는 대신 컬렉션에 무엇을 해야하는지 알려주십시오. 내부에 대해 뭔가

0x 표준은 클로저를 도입 할 예정이며,이 접근 방식은 사용이 훨씬 쉽게 사용 가능합니다. 예를 들어 Ruby 's의 표현력을 살펴보십시오. [1..6].each { |i| print i; }...

성능

그러나 아마도 많은 감독 된 문제는 for_each 접근 방식은 반복을 병렬화 할 수있는 기회를 제공합니다. 인텔 스레딩 블록 시스템의 프로세서 수보다 코드 블록을 배포 할 수 있습니다!

참고 : 발견 후 algorithms 도서관, 특히 foreach, 나는 2 ~ 3 개월 동안 엄청나게 작은 '도우미'운영자 스트러크를 작성하여 동료 개발자를 미치게 할 것입니다. 이 시간 후, 나는 실용적인 접근법으로 돌아갔습니다 - 작은 루프 바디는 foreach 더 이상은 없어 :)

반복자에 대한 반드시 참조는 책입니다 "확장 된 STL".

GOF는 반복자 패턴 끝에 작은 단락을 가지고 있으며,이 브랜드 반복에 대해 이야기합니다. 이를 '내부 반복자'라고합니다. 보세요 여기, 도.

더 객체 지향적이기 때문입니다. 인덱스로 반복하는 경우 다음을 가정합니다.

a) 해당 개체가 주문됩니다
b) 해당 개체는 색인으로 얻을 수 있습니다.
c) 인덱스 증분이 모든 항목에 도달합니다.
d) 그 지수는 0에서 시작한다

반복자를 사용하면 기본 구현이 무엇인지 알지 못하고 "내가 모든 것을주기 위해 나에게 모든 것을주기 위해 나에게 모든 것을 줘"라고 말합니다. (Java에는 색인을 통해 액세스 할 수없는 컬렉션이 있습니다)

또한 반복자를 사용하면 배열의 한계를 벗어나는 것에 대해 걱정할 필요가 없습니다.

반복자에 대한 또 다른 좋은 점은 그들이 당신의 const preence를 표현하고 시행 할 수 있다는 것입니다. 이 예제는 루프의 한가운데서 벡터를 변경하지 않도록합니다.


for(std::vector<Foo>::const_iterator pos=foos.begin(); pos != foos.end(); ++pos)
{
    // Foo & foo = *pos; // this won't compile
    const Foo & foo = *pos; // this will compile
}

다른 모든 훌륭한 답변을 제외하고 ... int 벡터에 충분히 크지 않을 수 있습니다. 대신 인덱싱을 사용하려면 size_type 컨테이너 용 :

for (std::vector<Foo>::size_type i = 0; i < myvector.size(); ++i)
{
    Foo& this_foo = myvector[i];
    // Do stuff with this_foo
}

아마도 당신이 전화 할 수 있다고 지적해야합니다

std::for_each(some_vector.begin(), some_vector.end(), &do_stuff);

STL 반복자는 대부분 정렬과 같은 STL 알고리즘이 컨테이너 독립성이 될 수 있도록 주로 존재합니다.

벡터의 모든 항목을 루프하려면 인덱스 루프 스타일을 사용하십시오.

대부분의 인간을 위해 타이핑이 적고 구문 분석하기가 더 쉽습니다. C ++가 템플릿 매직을 타지 않고 간단한 foreach 루프를 가지고 있다면 좋을 것입니다.

for( size_t i = 0; i < some_vector.size(); ++i )
{
   T& rT = some_vector[i];
   // now do something with rT
}
'

나는 그것이 벡터에 큰 차이를 만든다고 생각하지 않습니다. 나는 더 읽기 쉬운 것으로 간주하기 때문에 인덱스를 직접 사용하는 것을 선호하며, 6 개 항목을 뛰어 넘거나 필요한 경우 뒤로 점프하는 것처럼 임의의 액세스를 수행 할 수 있습니다.

나는 또한 이와 같은 루프 내부의 항목에 대한 참조를 좋아하므로 장소 주변에는 많은 사각형 괄호가 없습니다.

for(size_t i = 0; i < myvector.size(); i++)
{
    MyClass &item = myvector[i];

    // Do stuff to "item".
}

미래의 어느 시점에서 벡터를 목록으로 교체해야한다고 생각하면 반복기를 사용하는 것이 좋을 수 있으며 STL 괴물에 더 세련되게 보이지만 다른 이유는 생각할 수 없습니다.

두 번째 형태는 더 정확하게하고있는 일을 나타냅니다. 당신의 예에서, 당신은 i의 가치에 신경 쓰지 않습니다. 실제로 당신이 원하는 것은 반복자의 다음 요소입니다.

이 답변의 주제에 대해 조금 더 배운 후, 나는 그것이 약간의 지나치게 단순화되었다는 것을 알고 있습니다. 이 루프의 차이점 :

for (some_iterator = some_vector.begin(); some_iterator != some_vector.end();
    some_iterator++)
{
    //do stuff
}

그리고이 루프 :

for (int i = 0; i < some_vector.size(); i++)
{
    //do stuff
}

상당히 최소입니다. 사실, 이런 식으로 루프를 수행하는 구문은 나에게 성장하는 것 같습니다.

while (it != end){
    //do stuff
    ++it;
}

반복자는 상당히 강력한 선언적 기능을 잠금 해제하며 STL 알고리즘 라이브러리와 결합하면 Array Index Administrivia의 범위를 벗어난 멋진 멋진 작업을 수행 할 수 있습니다.

인덱싱에는 추가가 필요합니다 mul 작업. 예를 들어 vector<int> v, 컴파일러가 변환됩니다 v[i] ~ 안으로 &v + sizeof(int) * i.

반복하는 동안 처리 할 항목 수를 알 필요가 없습니다. 당신은 단지 아이템이 필요하고 반복자는 그런 일을 아주 잘합니다.

인접한 컨테이너에 추가 할 때 인수가 무효가되지 않는다는 점은 아직 언급되지 않았습니다. std::vector, 반복하는 동안 용기에 품목을 추가 할 수 있습니다.

반복자에게도 가능하지만 전화해야합니다. reserve(), 따라서 얼마나 많은 항목을 추가 할 수 있는지 알아야합니다.

이미 몇 가지 좋은 점이 있습니다. 몇 가지 추가 의견이 있습니다.

  1. C ++ 표준 라이브러리에 대해 이야기하고 있다고 가정하면 "Vector"는 C- 어레이를 보장하는 임의의 액세스 컨테이너 (임의 액세스, Contiguos 메모리 레이아웃 등)를 의미합니다. 'some_container'라고 말한 경우 위의 많은 답변이 더 정확했을 것입니다 (컨테이너 독립성 등).

  2. 컴파일러 최적화에 대한 종속성을 제거하려면 색인 코드에서 Loop에서 몇 가지 _Vector.size ()를 이동할 수 있습니다.

    const size_t numElems = some_vector.size();
    for (size_t i = 0; i 
  3. 항상 사전 증가 반복자를 예외적으로 처리하고 예외적 인 사례로 취급합니다.

for (some_iterator = nod_vector.begin (); some_iterator! = nome_vector.end (); ++ some_iterator) {// do do stuff}

따라서 가정 가능하고 색인이 가능합니다 std::vector<> 컨테이너와 마찬가지로, 컨테이너를 순차적으로 통과하는 다른 것을 선호할만한 이유는 없습니다. 구형 또는 최신 장군 인덱스를 자주 참조 해야하는 경우 인덱스 버전이 더 적합합니다.

일반적으로 반복자를 사용하여 알고리즘을 사용하고 반복자 유형을 변경하여 행동을 제어 (및 암시 적으로 문서화) 할 수 있기 때문에 선호됩니다. 배열 위치는 반복자 대신에 사용할 수 있지만 구문 차이가 튀어 나옵니다.

나는 같은 이유로 반복 기간을 사용하지 않습니다. 다수의 내부 루프가있을 때는 모든 로컬 값과 반복자 이름을 기억하지 않고도 글로벌/멤버 변수를 추적하기에 충분히 어렵습니다. 내가 유용한 것은 다른 경우에 두 가지 지수 세트를 사용하는 것입니다.

for(int i=0;i<anims.size();i++)
  for(int j=0;j<bones.size();j++)
  {
     int animIndex = i;
     int boneIndex = j;


     // in relatively short code I use indices i and j
     ... animation_matrices[i][j] ...

     // in long and complicated code I use indices animIndex and boneIndex
     ... animation_matrices[animIndex][boneIndex] ...


  }

예를 들어 "animation_matrices [i]와 같은 것들을 예를 들어 임의의 "anim_matrix"-이름 지정-타이터에 약칭하고 싶지도 않습니다. 왜냐하면이 값이 어떤 배열이 시작되는지 명확하게 볼 수 없기 때문입니다.

  • 금속에 가까이있는 것을 좋아한다면 / 구현 세부 정보를 신뢰하지 않는다면 사용하지 마십시오 반복자.
  • 개발 중에 다른 수집 유형을 정기적으로 전환하면 사용 반복자.
  • 다른 종류의 컬렉션을 반복하는 방법을 기억하기가 어렵다면 (아마도 여러 가지 다른 외부 소스의 여러 유형이있을 수 있음), 사용 반복자는 요소를 걷는 수단을 통일합니다. 이는 배열 목록으로 링크 된 목록을 전환하는 데 적용됩니다.

정말, 그게 전부입니다. 마치 평균적으로 더 많은 간결함을 얻는 것처럼 보이지 않으며 간결함이 실제로 목표라면 항상 매크로로 돌아갈 수 있습니다.

"CPU에게 무엇을 해야하는지"(명령 적)보다 "라이브러리에 원하는 것을 알려줍니다"(기능적)보다 훨씬 낫습니다.

따라서 루프를 사용하는 대신 STL에 존재하는 알고리즘을 배워야합니다.

컨테이너 독립성

많은 응용 프로그램에는 "디스플레이 썸네일 이미지"와 같은 것이 필요하기 때문에 항상 배열 인덱스를 사용합니다. 그래서 나는 다음과 같은 것을 썼습니다.

some_vector[0].left=0;
some_vector[0].top =0;<br>

for (int i = 1; i < some_vector.size(); i++)
{

    some_vector[i].left = some_vector[i-1].width +  some_vector[i-1].left;
    if(i % 6 ==0)
    {
        some_vector[i].top = some_vector[i].top.height + some_vector[i].top;
        some_vector[i].left = 0;
    }

}

두 구현이 모두 정확하지만 'for'루프를 선호합니다. 우리는 다른 컨테이너가 아닌 벡터를 사용하기로 결정 했으므로 인덱스를 사용하는 것이 가장 좋습니다. 벡터가있는 반복기를 사용하면 연속 메모리 블록에 객체를 갖는 데있어서 이점을 얻을 수 있습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top