디버그 반복기 지원

Visual C++ 런타임 라이브러리는 부정확한 반복기 사용을 검색하고 런타임에 대화 상자를 어설션하고 표시합니다. Debug Iterator Support를 사용하도록 설정하려면 프로그램 컴파일 시 C++ 표준 라이브러리 및 C 런타임 라이브러리의 디버그 버전을 사용해야 합니다. 자세한 내용은 CRT 라이브러리 기능을 참조하세요. 확인된 반복기를 사용하는 방법에 대한 자세한 내용은 확인된 반복기를 참조하세요.

C++ 표준은 멤버 함수로 인해 컨테이너에 대한 반복기가 어떻게 무효화되는지 설명합니다. 다음과 같은 두 가지 예가 있습니다.

  • 컨테이너에서 요소를 지우면 요소에 대한 반복기가 무효화됩니다.

  • push 또는 insert를 사용하여 vector의 크기를 줄이면 vector에 대한 반복기가 무효화됩니다.

잘못된 반복기

이 샘플 프로그램을 디버그 모드에서 컴파일하면 이 프로그램이 런타임에 어설션되고 종료됩니다.

// iterator_debugging_0.cpp
// compile by using /EHsc /MDd
#include <vector>
#include <iostream>

int main() {
   std::vector<int> v {10, 15, 20};
   std::vector<int>::iterator i = v.begin();
   ++i;

   std::vector<int>::iterator j = v.end();
   --j;

   std::cout << *j << '\n';

   v.insert(i,25);

   std::cout << *j << '\n'; // Using an old iterator after an insert
}

_ITERATOR_DEBUG_LEVEL 사용

전처리기 매크로 _ITERATOR_DEBUG_LEVEL을 사용하여 디버그 빌드에서 반복기 디버깅 기능을 끌 수 있습니다. 이 프로그램은 어설션하지 않지만 여전히 정의되지 않은 동작을 트리거합니다.

// iterator_debugging_1.cpp
// compile by using: /EHsc /MDd
#define _ITERATOR_DEBUG_LEVEL 0
#include <vector>
#include <iostream>

int main() {
    std::vector<int> v {10, 15, 20};

   std::vector<int>::iterator i = v.begin();
   ++i;

   std::vector<int>::iterator j = v.end();
   --j;

   std::cout << *j << '\n';

   v.insert(i,25);

   std::cout << *j << '\n'; // Using an old iterator after an insert
}
20
-572662307

초기화되지 않은 반복기

어설션은 다음과 같이 초기화되기 전에 반복기를 사용하려고 할 때도 발생합니다.

// iterator_debugging_2.cpp
// compile by using: /EHsc /MDd
#include <string>
using namespace std;

int main() {
   string::iterator i1, i2;
   if (i1 == i2)
      ;
}

호환되지 않는 반복기

for_each 알고리즘에 대한 두 개의 반복기가 호환되지 않으므로 다음 코드 예제는 어설션을 발생시킵니다. 알고리즘은 알고리즘에 제공되는 반복기가 같은 컨테이너를 참조하는지 확인합니다.

// iterator_debugging_3.cpp
// compile by using /EHsc /MDd
#include <algorithm>
#include <vector>
using namespace std;

int main()
{
    vector<int> v1 {10, 20};
    vector<int> v2 {10, 20};

    // The next line asserts because v1 and v2 are
    // incompatible.
    for_each(v1.begin(), v2.end(), [] (int& elem) { elem *= 2; } );
}

이 예제에서는 함수 대신 람다 식 [] (int& elem) { elem *= 2; }를 사용합니다. 이 선택은 어설션 실패에 아무런 영향을 주지 않지만 유사한 펀터가 동일한 오류를 발생시키는 경우 람다는 짧은 코드 블록을 작성하는 방법입니다. 람다 식에 대한 자세한 내용은 람다 식을 참조하세요.

범위를 벗어난 반복기

디버그 반복기 확인을 실행하면 for 루프 범위가 끝날 때 루프에 선언된 반복기 변수가 for 범위를 벗어납니다.

// iterator_debugging_4.cpp
// compile by using: /EHsc /MDd
#include <vector>
#include <iostream>
int main() {
   std::vector<int> v {10, 15, 20};

   for (std::vector<int>::iterator i = v.begin(); i != v.end(); ++i)
      ;   // do nothing
   --i;   // C2065
}

디버그 반복기에 대한 소멸자

디버그 반복기에 non-trivial 소멸자가 있습니다. 소멸자가 실행되지 않지만 개체의 메모리가 해제되면 액세스 위반 및 데이터 손상이 발생할 수 있습니다. 다음 예제를 고려해 보세요.

// iterator_debugging_5.cpp
// compile by using: /EHsc /MDd
#include <vector>
struct base {
   // TO FIX: uncomment the next line
   // virtual ~base() {}
};

struct derived : base {
   std::vector<int>::iterator m_iter;
   derived( std::vector<int>::iterator iter ) : m_iter( iter ) {}
   ~derived() {}
};

int main() {
   std::vector<int> vect( 10 );
   base * pb = new derived( vect.begin() );
   delete pb;  // doesn't call ~derived()
   // access violation
}

참고 항목

C++ 표준 라이브러리 개요