[42Seoul] - ft_containers

Joey·2023년 2월 6일
0

42 SEOUL

목록 보기
19/20



1.무엇을 하는 과제인가?

: cpp의 stl을 구현하는 과제이다.
-.stl이란, 표준 CPP Library(Standard Template Library)로서 자주 사용되는 자료구조와 알고리즘을 모아 만든 Library이다.

-.들어가기에 앞서
: 이 과제를 시작하기 전 부터 계속 어떤 것을 얻어가라고 이 과제를 만들었을지에 대해서 고민이 많았다. 나는 이렇게 생각을 해보려고 한다.

1)말도 안되는 코드들을 보더라도 언젠가는 이해하는 순간들이 온다.
2)표준 문서들을 보기 싫어도 보는 습관들을 가져보자.

사실 stl을 이해하고, cpp의 다양한 기능들을 써보고 이런 것에 앞서 이 과제를 통해서 위의 두가지를 느꼈던 것 같다.




2.과제를 하면서 참고 했던 곳들

1)CPP 기본

: 이 두 곳은 설명을 하지 않더라도 기본적으로 참고를 할 수 밖에 없는 곳들이다. 해당 stl이 어떤 기능을 가지고 있는지 정리가 되어 있고 예제 또한 같이 있다.

cpp reference
링크 : http://cppreference.com/

cplusplus
링크2 : https://cplusplus.com/


2)도서

-.뇌를 자극 하는 stl
: stl관련 정보들은 인터넷으로 충분히 알 수는 있지만, 책으로 봤을때 이해도가 확연히 늘어났다. 그림으로 각 자료구조에 대해서 설명을 해주었는데 이해가 잘 되어서 좋았다. 가장 먼저 읽기를 추천한다.

-.effective stl
: 아래는 effective stl 책을 요약해 둔 곳이다. 일정부분 읽어보면 컨테이너 과제를 할때 도움이 된다. 필요한 곳만 훑어서 읽기를 권한다.
링크 : http://ajwmain.iptime.org/programming/book_summary/%5B02%5Deffective_stl/effective_stl.html


3) 정리를 잘하신 분

: 일면식도 없는 분이지만, 정말 정리를 잘하셨다. 사실 처음에는 보고 이해가 잘 가지 않았지만 어느 정도 이해를 하고 다시 보니 정리를 잘하셨다는 게 느껴졌다.

링크 : https://github.com/yongjulejule/ft_containers/


4) 자료구조 시각적으로 볼 수 있는 곳

: 자료구조는 눈으로 보고 구현을 해보는 것이 좋다고 생각한다. 이전에 알게 된 곳들이지만 많은 분들이 보고 이해를 하면 더 좋을 것 같다.

-.visu algo
: rb tree를 제외하고 모든 것을 시각적으로 볼 수 있다.

링크 : https://visualgo.net/en/

-.red black tree 시각화
: visu algo에 없는 rb tree를 이곳에서 볼 수 있다

링크 : https://www.cs.usfca.edu/~galles/visualization/RedBlack.html


5)모두의 코드 관련 자료

: 믿고보는 모두의 코드의 stl 관련 내용이다.

링크 : https://modoocode.com/223


6)gcc 2001년도 버전

: 구현해야 되는 것은 역시나 cpp 98버전이다. 최근 것은 참고만 하되, 결론은 예전 버전을 토대로 작성을 해야한다. 아래의 깃허브를 다운을 받고 git commit을 되돌리면 된다.

gcc 98 version
1.git clone
https://github.com/gcc-mirror/gcc.git
2.git commit 2001년도로 돌리기
git checkout bf3b866e31f8d5fb33f0d86d844abf2d2a4896a9
3.folder찾기
gcc/libstdc++-v3/include/bits/stl_vector.h

7)ea stl

: 예전 stl만 보는 것보다 한번쯤은 최신 stl을 봐보는 것도 좋습니다. 기존에 가지고 있는 stl도 좋지만 ea에서 사용하고 있는 stl이니 같이 참고해서 공부하시면 좋습니다.

링크 : https://github.com/electronicarts/EASTL


8)red black tree 관련 영상

: rb tree는 이해하기가 그다지 쉽지 않다. 한국어로 설명을 정말 잘하신분이 있으니 참고를 하자.

링크 : https://www.youtube.com/watch?v=2MdsebfJOyM

-.추가로 정리했던 노션도 공유해 본다.
링크 : https://little-crown-b73.notion.site/Red-Black-Tree-cbffb4ac57f94fbcad2a0ef67a8727be


9)flow map을 그려볼 수 있는 곳

: flow map을 그리는 가장 유명한 곳은 draw.io로 알고 있다. 하지만 좀 더 알록달록한 것을 좋아한다면 피그마가 좋다고 생각한다. 이번에 자료구조가 제대로 이해가 안가서 flow map을 그려보고 이해를 해보았는데 도움이 굉장히 많이 되었다.

링크 : https://www.figma.com/


3.과제를 하면서 공부했던 것들

1)Template meta programing

: template meta programming의 정의는 이렇다.(위키백과)
템플릿을 사용하는 프로그래밍 기법으로, 컴파일러에게 프로그램 코드를 생성하도록 하는 방식이다. 이러한 기법은 컴파일 시점에 많은 것을 결정하도록 하여, 실행 시점의 계산을 줄여준다.

cpp에서는 이 방식을 활용하여 런타임 시점의 계산을 줄이고 컴파일 시점에 많은 것을 결정시킨다는 것이 중요하다. 이 과제를 시작한다면 이 부분부터 이해를 하고 가는 것이 좋다.

vector가 무엇인지, map이 무엇인지를 이해하는 것도 중요하나 그것보다 이게 대체 무엇인지에 대해서 몸으로 느껴야 만드는데 어렵지 않다.

나의 경우 이것에 대해서 익숙해지지 않은 상태에서 자꾸 다른 것들을 습득하다보니 효율이 굉장히 낮아졌던 것 같다. 흔히 우리는 이런 자료구조를 구현해보면서 공부를 많이 하게 된다.

처음에 자료구조만 공부하라고 하는 과제였다면 그게 맞으나 이 과제는 cpp의 기능들을 어떻게 활용해 가지는지에 대해서 알아가는 과제라고 생각한다. 그것의 중심에는 template meta programming이 있다.

어렵게 써놔서 그렇지 템플릿이라는 도구로 compile 할 때에 원하는 코드로 입맛대로 만들어 가는 것을 말한다.

template <class _Tp1, class _Tp2>
int (_Tp1 arg1, _Tp2 arg2)
{

}

template <class _Tp1, class _Tp2, class _Tp3>
int (_Tp1 arg1, _Tp2 arg2, _Tp3 arg3)
{

}

위와 같이 여러개의 템플릿들이 있고, 우리가 원하는 상황에 원하는 결과가 나오도록 입맛대로 만들어 준다. 런타임에 한다고 하면 항상 해왔던 if을 가져와서 하겠지만, compile에는 그게 힘드니 다양한 꼼수(?)들이 만들어져 있는 cpp이다.

2) SFINAE(Substitution Failure Is Not An Error)

: 사실 처음 이 단어를 봤을때 너무 거부감이 들고 어려웠다. 관련되서 여러 설명들이 있을테니 나는 조금이라도 더 쉽게 말을 해보고 싶다. 이 단어 뜻만 본다면 "치환 실패는 에러가 아니야"라는 뜻이다. 말그대로 컴파일 에러를 내지 않고 그냥 제낀다.

: template mate programming에서 입맛대로 쓰고 싶을때 쓴다고 했다. 컴파일러는 코드를 훑으면서 template이 해당되는 조건이 아닐때 에러를 안내고 그냥 제끼면서 다른 것들을 찾아간다. 막상 내용 자체는 별것이 없다. 쉽게 이해하고 부가적인 것은 그 다음에 공부해보도록 하자. overloading 관련하여 방대한 설명은 아래에 나와있다.

링크 : https://en.cppreference.com/w/cpp/language/overload_resolution

3) enable_if & is_integral

: 이것도 쉽게 생각을 해보자. template meta programing을 할 때에 if문 같은 것을 쓰고 싶다고 해보자. 이걸 어떻게 할 것인가?? enable_if가 비슷한 예라고 생각을 하면 된다.

-.enable_if

	//enable_if
	template<bool B, typename T = void>
	struct enable_if {};
    
	template<typename _Tp>
	struct enable_if<true, _Tp>
	{
		typedef _Tp type;
	};
    

일단 위의 enable_if를 본다면 위쪽이 기본 형태이고, 아래쪽은 true일 경우 어떻게 되는지에 대해서 나타나 있다.

한마디로 true일 경우에 typedef _Tp type이 된다는 것을 알 수 있게 된다.

왜 굳이 이렇게 하냐고 생각할 수는 있지만 compile time에 할 수 있는 방법으로 if문을 쓴다고 생각을 하면 된다.

-.is_integral

	// integral type
	//false
	template <typename T>
	struct is_integral : public false_type {};

	//true
	template<>
	struct is_integral< bool > : public true_type {};

: is_integral도 어렵게 생각하지 말자, 기존에 우리가 써왔던 자료형들 int, float, long 등등이 integral이고 이것인지를 확인해가는 과정이다. 맞으면 true, 아니면 false이다.

이것을 굳이 하는 이유는 iterator인지 아닌지를 구별하기 위해서 사용한다. iterator면 다른 방식으로 작동을 하게 하고 싶어서 한다고 생각을 하면 된다.

-.그래서 어떻게 쓰는데?
: 아래의 예제를 본다면 어떤 생각이 들까? 잘 아는 사람들이야 이해가 가겠지만 모르는 사람들은 처음 보는 순간 창을 닫고 싶을 것이다.

	template <class _InputIterator >
		vector(
			typename ft::enable_if<!ft::is_integral<_InputIterator>::value, _InputIterator>::type _first,
			_InputIterator _last,
			const allocator_type &alloc = allocator_type())

위의 예제는 간단하게 다시 써본다면 이런 것이다.

	template <class _InputIterator >
		vector(
			_InputIterator _first,
			_InputIterator _last,
			allocator_type())

여기서 세번째 인자는 이야기하는 주제가 아니니 잠깐 생략을 해보고 이야기를 한다면

typename ft::enable_if<!ft::is_integral<_InputIterator>::value, _InputIterator>::type _first

이렇게 길었던 인자가

_InputIterator _first

이렇게 줄었다.

하나씩 뜯어보자면

!ft::is_integral<_InputIterator>::value

이것은 들어간 type인 InputIterator(말만 인풋 이터레이터임, int가 들어갈 수도 있음)가 is_integral인지 확인하는 단계이다. 만약에 integral(int나 float등)이라면 true를 반환을 하게 된다. 그러면 !(true)이므로 결과적으로는 false가 되게 된다.

반대로 iterator면 true가 되게 되고 enable_if에 true를 넣어주게 된다.

ft::enable_if<true, _InputIterator>::type _first,

enable_if는 true일 경우 두번째로 들어온 _InputIterator를 반환하게 설계가 되어있다. 결과론적으로 아래만 남게 된다.

_InputIterator _first,

위에서도 이야기 하였듯 이렇게 복잡하게 하는 이유는 컴파일 타임에 할 수 있는 방법으로 if문 비슷하게 하고 싶어서 이다. 눈에 익숙해지기 전까지는 꽤나 고통을 받았었다... 나중에 알고나서는 별게 아니라는 것을 알게 되었다.


4.회고

1)공식 문서

: cpp에서는 cppreference와 cplusplus가 나름 공식문서라고 생각을 한다. 항상 번역을 해보거나 다른 곳을 많이 찾아보거나 했었는데 이번 과제에서는 최대한 영어로 읽어보려고 노력하였다. 그럼에도 불구하고 아직도 완벽하게 익숙치는 않은 것 같다. 되도록 공식문서를 자주 봐야겠다는 생각을 하였다.

2)자신감을 하락시키는 방대한 코딩량들

: 사실 gcc버전을 굉장히 많이 참고해서 손수 한땀한땀 받아 쳤는데, 하루 아침에 받아쓸만한 양이 아니다.... 과제를 하다보니 하도 답답해서 복붙을 해서 돌려본적이 있지만 연결된 것들이 하도 많아서 그렇게는 되지 않았고, 수많은 컴파일 에러(50번은 난것 같은..)를 통하여 겨우 한번 돌려보게 되었다.
런타임 에러들은 고치기가 쉬운데 컴파일 에러는 보이는 에러 메시지와 다른 경우가 종종 있어서 결국에는 전체적인 코드 관점으로 접근을 해야하기도 했다. 이 과제를 하면서 자신감이 많이 하락하였는데, 안되는 것을 계속 붙잡는 것보단 다른 것을 하면서 나중에 한번 다시 보는게 좋다는 생각을 하였다.

3)원초적인 고민들

: 분명 차근차근 책도 읽고, 조언도 받았고, 스터디도 하였고, 참고문서들도 참고했고, 다른 분들의 코드도 보면서 진행하였는데 마음대로 진행이 되지 않는 부분들이 많았다. 꼼꼼하지 못한 부분들 때문인건지 실력이 부족한 것인지 어떤 것들인지는 모르겠지만 다음 과제에 앞서서 정말 고민이 되는 부분이다. 잘하시는 몇몇분들 처럼 따라해보려 해도 이게 쉽지 않다는 생각이 많이 들었다. 이번 과제의 중반부 이후로 길을 잃은 감도 있고, 많이 힘겨워했던게 느껴졌다. 다음 과제는 되도록 스케치를 잘해서 시간이 걸리더라도 만족할 수 있는 과제가 되었으면 좋겠다.

profile
세상을 이롭게 하는 프로그램 만들기

2개의 댓글

comment-user-thumbnail
2023년 3월 2일

치환 실패는 에러가 아니야~

1개의 답글