본문 바로가기
C++/기초

C++ 기초 : iterator (3)

글: 시플마 2024. 4. 22.

직접 구현한 vector(가변 배열) 역할을 하는 

클래스 cArr의 inner 클래스 iterator가 역참조(*) 연산을

할 수 있도록 연산자 오버로딩을 진행하겠습니다.

 

 

해당 작업을 위해선 우선 iterator 클래스의 

멤버를 수정할 필요가 있습니다.

 

iterator는 가변 배열의 시작 주솟값을 갖고 있습니다.

근데 가변 배열은 데이터 삽입 과정에서 공간이 가득 차면

새로운 공간을 할당한 후 기존 데이터를 복사하고

기존 데이터가 있던 공간을 해제하죠?

 

즉 공간이 가득 차서 새로운 공간이 할당되면

iterator가 갖고 있는 가변 배열의 주솟값이 유효하지 않다는 거죠.

 

 

여기서 생각해 볼 수 있는 것은

iterator의 멤버 m_pData가 가변 배열의 시작 주솟값을

저장하고 있습니다. 근데 어차피 vector도 멤버 m_pData에

가변 배열의 시작 주솟값을 갖고 있고 

공간이 가득 차서 새로운 공간을 가리키게 되어도

이것이 vector의 m_pData에 반영됩니다.

 

그러므로 iterator의 멤버 m_pData를 없애고 

vector 자체를 iterator의 멤버로 하여 새로운 공간을

가리키는 주솟값이 알아서 갱신되게 하는 방법이 있죠.

 

 

또는 위 그림과 같은 상황, 

즉 iterator가 기존의 가리키던 공간이 사라졌을 경우

오류로 인지하게 하는 방법이 있습니다.

 

iterator의 멤버 m_pData를 그대로 두고

vector 자체도 멤버로 추가하여 이 둘이

갖고 있는 주솟값을 비교하여 다른 경우

오류를 출력하는 것이죠.

 

표준 라이브러리를 통해 제공되는 vector에서는

위와 같은 경우 오류로 인식하므로 

저도 오류를 출력하는 방식으로 구현하겠습니다.

 

 

iterator 클래스를 수정하였습니다.

 

vector를 가리킬 수 있도록 cArr형 포인터 멤버 m_pArr를 추가하였습니다.

 

이에 따라 초기화를 진행하는 생성자도 수정하였습니다.

 

기본 생성자의 경우 m_pArr을 nullptr로 초기화하고 

인자를 받는 생성자의 경우 m_pArr을 vector의 

주솟값으로 m_pArr를 초기화합니다.

 

 

참고로 iterator는 cArr의 inner 클래스이기 때문에 

cArr의 private로 선언된 멤버를 iterator 클래스에서 접근할 수 있습니다.

 

 

 

 

 


 

 

 

이번에는 begin과 end 함수를 구현하겠습니다.

 

vector의 시작 주솟값을 반환하는 begin 함수의 경우

두 가지 경우가 있을 겁니다.

 

가변 배열이 존재하지 않는 경우와 가변 배열이 있는 경우죠.

 

가변 배열이 존재하지 않는 경우는

cArr에서 데이터의 개수를 나타내는 m_iCount가 0일 때겠죠?

 

그럴 때 begin 함수는 iterator를 반환하는데 

해당 iterator 멤버에 begin 함수를 호출한 vector 자신과 vector가

갖고 있는 시작 주솟값(가변 배열이 존재하지 않는 경우니까 nullptr이겠죠.)과

-1을 인자로 넘깁니다. (iterator의 멤버 idx의 값이 -1이면 데이터가 없는 것으로 

간주합니다.)

 

 

근데 데이터가 이미 존재하는 경우,

iterator 멤버 idx에는 0을 넘기죠.

현재 iterator가 가리키는 곳은 0번째 인덱스임을 의미합니다.

 

 

end 함수를 호출하는 경우 

end iterator를 반환합니다.

즉 실제 데이터가 없는, 단순히 끝임을

의미하는 iterator를 반환하는 것이죠.

iterator의 멤버 idx의 값이 -1이면 데이터가

없는 것으로 간주하므로 -1을 인자로 넘기는 모습입니다.

 

 

 


 

 

 

이제 역참조 연산자를 오버로딩하겠습니다.

 

iterator를 역참조하면 

해당 iterator가 가리키는 곳에 값을 얻어낼 수 있어야 합니다.

가변 배열 공간을 가리키는 포인터 m_pData를 통해

인덱스에 접근하고 그것을 반환하면 되죠.

 

 

여기서 예외로 iterator의 idx 값이 -1이거나(가변 배열이 존재하지 않음)

또는 vector가 저장하고 있는 가변 배열의 시작 주솟값과

iterator가 저장하고 있는 가변 배열의 시작 주솟값이 

다르면 오류를 띄웁니다.

 

 

또한 역참조 연산자를 통해 해당 공간에 있는

값을 얻어내는 것뿐만 아니라 

해당 공간에 접근하여 값을 수정하는 것도

가능해야 합니다.

이를 위해 공간 자체를 반환해야 하기 때문에 

T형 레퍼런스로 반환하는 것이죠.

 

 

 


 

 

 

 

이후에는 증감 연산자도 오버로딩할 건데

주의해야 할 점이 몇 개 있습니다.

 

end를 가리키는 iterator에

++ 연산을 하여 end를 넘는 것

 

begin을 가리키는 iterator에 -- 연산을 하여

begin 이전으로 가는 것입니다.

 

해당 경우 모두, 표준 라이브러리에서 

제공하는 vector에서 오류로 인지하고 있습니다.

 

 

간략하게 ++과 -- 연산자 오버로딩을 하였습니다.

 

반환 타입이 iterator형 레퍼런스인 이유를 살펴 봅시다.

 

만약 

 

int k = 0;

++(++k);

 

위와 같은 코드가 있을 때

첫 ++ 연산을 한 후

 

++(k)가 되는 것이죠?

 

즉 첫 번째 ++ 연산 이후, k가 반환되고

그 k에 다시 ++ 연산을 하는 것입니다.

 

iterator도 이러한 연산을 하려면 ++ 연산 이후

자신이 가리키는 공간 자체를 반환해야,

다음 ++ 연산을 이어서 할 수 있으므로

레퍼런스로 반환하는 것입니다.

 

 

 

 

 

강의 출처 : https://www.youtube.com/watch?v=PFc4g8mxOiI&list=PL4SIC1d_ab-aOxWPucn31NHkQvNPHK1D1&pp=iAQB


 

 

 

'C++ > 기초' 카테고리의 다른 글

C++ 기초 : iterator (5)  (0) 2024.04.22
C++ 기초 : iterator (4)  (0) 2024.04.22
C++ 기초 : iterator (2)  (0) 2024.04.20
C++ 기초 : iterator (1)  (0) 2024.04.20
C++ 기초 : STL (vector와 list)  (0) 2024.04.20