Search

vector의 내부 원소 참조

Created
2021/02/26
tag
C++
vector
[] 연산자
at
vector에서 내부에 홀딩하고 있는 데이터를 참조하기 위한 방법은 2가지가 있다.
[] 대괄호 연산자를 이용한 참조
vectorat이라는 멤버 함수를 이용한 참조
vector에서 [] 대괄호 연산자는 내부의 Overloading 함수로 작동한다. 즉, 기본적으로 지원되는 연산자가 아닌 해당 연산자를 재정의하여 구현되어 있는 것을 의미한다.
a라고 하는 vector가 위와 같이 존재하고, a-1번째 데이터는 존재하지 않지만 메모리에 빽뺵한 형태로 잡혀 있어서 주소 참조로 접근은 가능한 상태라고 생각해보자.

1. [] 연산자를 이용한 접근

[]를 이용하여 -1번째 데이터를 참조하려고 할 때, []는 주소에 대한 오프셋 계산만을 수행하여 접근하기 때문에 계산된 주소가 유효한 공간이라면 접근이 가능하다.
위의 전제에서는 메모리가 빽뺵한 형태로 잡혀 있어서 a0번째 데이터 이전이 접근 가능한 공간이기 때문에, Segmentation Fault가 발생하지 않을 뿐더러 -1번째 데이터는 a의 원소가 아님에도 별도의 오류를 발생시키지 않는다.

2. at 멤버 함수를 이용한 접근

[] 연산자를 이용했던 것과 달리 at이라는 멤버 함수를 사용하면, 주소에 대한 참조를 해주면서도 vector 클래스가 갖고 있는 원소에 대해서만 참조할 수 있도록 해준다. 따라서 at을 이용하여 -1번째 데이터에 접근하려고 a.at(-1)과 같이 호출하면 명확한 오류를 뱉어준다. 즉, 명확히 vector 내의 데이터만을 참조할 수 있도록 만들어주기 때문에 [] 연산자에 비해서 상대적으로 안전하게 사용할 수 있도록 해준다.
내부적으로는 접근하면 안 되는 곳에 대해서 인자를 받으면 ExceptionThrow하도록 Wrapping 되어 있다. 아래 코드는 vector.h의 내용인데, at 함수가 Range Error를 체크하는 것을 볼 수 있다.
reference operator[](size_type __n) { return *(begin() + __n); } const_reference operator[](size_type __n) const { return *(begin() + __n); } #ifdef __STL_THROW_RANGE_ERRORS void _M_range_check(size_type __n) const { if (__n >= this->size()) __stl_throw_range_error("vector"); } reference at(size_type __n) { _M_range_check(__n); return (*this)[__n]; } const_reference at(size_type __n) const { _M_range_check(__n); return (*this)[__n]; } #endif /* __STL_THROW_RANGE_ERRORS */
C++

3. 정리

따라서 index에 대한 철저한 관리가 된다면 별도의 검증이 들어가 있지 않은 []써도 무방하고, 꼭 안전하게 쓰고 싶다하면 at을 쓰시면 되겠습니다. 이에 대해서 at 메소드는 안전을 지향하는 만큼 []와 비교했을 때 속도 차이가 조금은 납니다. 하지만 이게 성능적으로 문제를 일으킬만큼의 유의미한 속도차이는 아닙니다. (수치적으로 5~̆̈10배 정도 차이가 난다고 해도 말이죠.) 그래서 그냥 편한거 쓰시면 되겠습니다.

4. Reference