STL
Standard Template Library의 약자
STL을 사용하면 각종 자료형에 구애받지 않는
통합 라이브러리 (유용하게 활용가능한 소스코드나 모듈)을 만들 수 있으며
C++의 STL은 다른 언어 Generic과는 다르게 굉장히 빠른 실행 퍼포먼스를 약속한다.
template <typername T>
STL 클래스에서 타입을 나중에 지정하겠다고 명시하는 방법
여기에서 이 T가 나중에 지정할 타입이름이 된다
안에 있는 내부의 클래스의 어떤 타입을 나중에 이것의 인스턴스를 만들 때 지정할 수 있도록 선언
#define _CRT_SECURE_NO_WARNINGS #include <cstdio> #include <string> template <typename T> // 이 클래스 내부에는 타입이 지정되지 않은 어떤 것이 있다, 타입의 지정을 뒤로 미룰 수 있다 class MyClass { public: T value; }; template <typename T> void swap(T* a, T* b){ // 모든 타입에서 가능한 swap T tmp; tmp = *a; *a = *b; *b = tmp; } int main() { MyClass<int>* m = new MyClass<int>(); // value는 이 인스턴스에서는 int다 m->value = 100; MyClass<std::string>* ms = new MyClass<std::string>(); // MyClass에 std string을 typename으로 지정하고 포인터로 선언 ms->value = "Hello World"; // 여기서부터 ms의 value는 문자열 int value1 = 100; int value2 = 200; swap<int>(&value1, &value2); // swap이라는 함수는 T가 int라는 타입으로 변환되는것 printf("value1 : %d\n", value1); printf("value2 : %d\n", value2); /* std::string에서도 대응 가능 std::string value1 = 100; std::string value2 = 200; swap<std::string>(&value1, &value2); printf("value1 : %d\n", value1.c_str()); printf("value2 : %d\n", value2,c_str()); */ return 0; } |
STL - 가변 배열 클래스 작성
STL의 방법을 활용하여 가변 배열 클래스를 작성한다.
이를 통해 코드의 재사용성을 늘리는
필요할때마다 그때그때 모든 코드를 하나하나 만드는 것이 아닌
하나의 통합적인 자료관리 모델을 만들고
이를 활용하는 코드를 생산해본다.
고정배열은 크기를 지정해놓고 나중에 그 크기를 변경을 할 수가 없다.
가변배열을 template 클래스로 만들어보기
최초의 MyArray라는 클래스를 선언하게 되면 이 MyArray라는 클래스에서
arrayItem을 동적할당으로 만들어주게 된다.
그 동적할당으로 만들어진 크기는 capacity, 처음에는 8
어떤 값이 카운트를 통해 배열로 추가가 되는데 처음에는 8
그 8을 넘어간다면?? 그러면 배열 포인터를 다시 초기화하여 크기를 더 크게 만들어주기
#define _CRT_SECURE_NO_WARNINGS #include <cstdio> #include <string> template <typename T> class MyArray { public: T* arrayItem; // 배열포인터 // arrayItem이라고 하는 변수는 뭔지 모르겠지만 나중에 type지정해주고 배열 포인터로 활용 int count = 0; // 배열아이템에 값을 추가를 해 주려면 arrayItem에 몇개의 배열 원소가 있는지 카운트 int capacity = 8; // 배열이 최대로 가질 수 있는 크기 MyArray() { // T* arrayItem; 처음에 고정배열, 생성자에서 초기화 해주기 arrayItem = new T[capacity]; } virtual ~MyArray() { // 소멸자 delete[] arrayItem; // 메모리해제 } void putValue(T value) { // arrayItem에 값을 집어넣을때 사용 if (capacity > count) { arrayItem[count] = value; count++; } else { // capacity는 1부터 시작 count는 0부터 시작 printf("배열의 캐파시티가 두 배로 늘어났습니다\n"); T* newarray = new T[capacity * 2]; capacity = capacity * 2; // capacity가 올라간 만큼에서 다시 배열 채워지게 // 어떤 값이 카운트를 통해 배열로 추가가 되는데 처음에는 8 //그 8을 넘어간다면?? 그러면 배열 포인터를 다시 초기화하여 크기를 더 크게 만들어주기 for (int i = 0. ; i < count; i++) { newarray[i] = arrayItem[i]; // 기존의 배열값을 복사해서 새로운 배열에 할당을 해주고 // 그 다음 새로 들어오는 putValue(T value) 값을 집어넣기 } delete [] arrayItem; // 기존 arrayItem free해주기 arrayItem = newarray; // newarray를 2배를 가진 새로운 arrayItem에 넣어주기 arrayItem[count] = value; count++; } } }; int main() { MyArray<int> m = MyArray<int>(); // MyArray 정적으로 만들기 m.putValue(100); m.putValue(200); m.putValue(300); m.putValue(400); m.putValue(500); m.putValue(600); m.putValue(700); m.putValue(800); m.putValue(900); for (int i = 0; i < m.count; i++) { printf(" %d ", m.arrayItem[i]); } return 0; } |
위 코드 깔끔하게 정리
(for문)
#define _CRT_SECURE_NO_WARNINGS #include <cstdio> #include <string> template <typename T> class MyArray { private: // arrayItem과 capacity를 이 클래스를 사용하는 사람이 보지못하도록 막는다. T* arrayItem; int count = 0; int capacity = 8; public: MyArray() { // 생성자 arrayItem = new T[capacity]; } virtual ~MyArray() { // 소멸자 delete[] arrayItem; // 메모리해제 } void putValue(T value) { // arrayItem에 값을 집어넣을때 사용 if (capacity <= count) { printf("배열의 캐파시티가 두 배로 늘어났습니다\n"); T* newarray = new T[capacity * 2]; capacity = capacity * 2; for (int i = 0. ; i < count; i++) { newarray[i] = arrayItem[i]; } delete [] arrayItem; // 기존 arrayItem free해주기 arrayItem = newarray; // newarray를 2배를 가진 새로운 arrayItem에 넣어주기 } arrayItem[count] = value; count++; } int getCount() { return count; // count숫자 리턴 } T getValue(int index) { // index위치에 있는 array배열 변수의 값을 리턴 return arrayItem[index]; } }; int main() { MyArray<int> m = MyArray<int>(); m.putValue(100); m.putValue(200); m.putValue(300); m.putValue(400); m.putValue(500); m.putValue(600); m.putValue(700); m.putValue(800); m.putValue(900); for (int i = 0; i < m.getCount(); i++) { printf(" %d ", m.getValue(i)); } return 0; } |
문자열인 경우
#define _CRT_SECURE_NO_WARNINGS #include <cstdio> #include <string> template <typename T> class MyArray { private: // arrayItem과 capacity를 이 클래스를 사용하는 사람이 보지못하도록 막는다. T* arrayItem; int count = 0; int capacity = 8; public: MyArray() { // 생성자 arrayItem = new T[capacity]; } virtual ~MyArray() { // 소멸자 delete[] arrayItem; // 메모리해제 } void putValue(const T& value) { // 레퍼런스로 받아오면 값복사 시간이 줄어든다 // const로 받아오게 되면 이 변할 수 없는 상수형의 문자열의 레퍼런스라는 의미가 된다 if (capacity <= count) { printf("배열의 캐파시티가 두 배로 늘어났습니다\n"); T* newarray = new T[capacity * 2]; capacity = capacity * 2; for (int i = 0. ; i < count; i++) { newarray[i] = arrayItem[i]; } delete [] arrayItem; // 기존 arrayItem free해주기 arrayItem = newarray; // newarray를 2배를 가진 새로운 arrayItem에 넣어주기 } arrayItem[count] = value; count++; } int getCount() { return count; // count숫자 리턴 } T getValue(int index) { // index위치에 있는 array배열 변수의 값을 리턴 return arrayItem[index]; } }; int main() { MyArray<std::string> m = MyArray<std::string>(); m.putValue("a"); m.putValue("b"); m.putValue("c"); m.putValue("d"); m.putValue("e"); m.putValue("f"); m.putValue("g"); m.putValue("h"); m.putValue("i"); for (int i = 0; i < m.getCount(); i++) { printf(" %s ", m.getValue(i).c_str()); } return 0; } |
STL 선언과 정의 분리
STL은 선언과 정의를 분리할 수 없다.
이유는 C++ 컴파일러가 그때그때 필요한 타입에 맞는 STL클래스를 가져와서
그것을 이용해 STL 클래스 몸체를 만들거나
STL 함수를 만들기 때문이다.
마치 전처리기 (매크로) 와 같은 동작을 하는 것이 STL이기 때문이다.
때문에 STL 클래스는 보통 헤더파일에만 존재하게 된다.
과제형 연습 프로그래밍
#define _CRT_SECURE_NO_WARNINGS #include <cstdio> #include <string> template <typename T> class MyArray { private: // arrayItem과 capacity를 이 클래스를 사용하는 사람이 보지못하도록 막는다. T* arrayItem; int count = 0; int capacity = 8; public: MyArray() { // 생성자 arrayItem = new T[capacity]; } virtual ~MyArray() { // 소멸자 delete[] arrayItem; // 메모리해제 } void putValue(const T& value) { //레퍼런스로 받아오면 값복사 시간이 줄어든다 // const로 받아오게 되면 이 변할 수 없는 상수형의 문자열의 레퍼런스라는 의미가 된다 if (capacity <= count) { printf("배열의 캐파시티가 두 배로 늘어났습니다\n"); T* newarray = new T[capacity * 2]; capacity = capacity * 2; for (int i = 0. ; i < count; i++) { newarray[i] = arrayItem[i]; } delete [] arrayItem; // 기존 arrayItem free해주기 arrayItem = newarray; // newarray를 2배를 가진 새로운 arrayItem에 넣어주기 } arrayItem[count] = value; count++; } int getCount() { return count; // count숫자 리턴 } T getValue(int index) { // index위치에 있는 array배열 변수의 값을 리턴 return arrayItem[index]; } // value 값이 존재하는지 확인하는 함수 bool contains(T value) { for(int i = 0; i < count; i++) { if (value == arrayItem[i]) { return true; } } return false; } // 값을 변경 void replace(int index, T value) { if (index < count) { arrayItem[index] = value; } } // 값을 삭제 (단, 빈 공간을 채워줘야 함) void erase(int index) { for(int i = index; i < count-1; i++) { // count까지 가면 안된다. // i+1번째에서 i번째에 값을 하나씩 넣어주면 된다. arrayItem[i] = arrayItem[i + 1]; } count--; // 카운트를 1줄인다. } }; int main() { MyArray<int> m = MyArray<int>(); m.putValue(10); m.putValue(11); m.putValue(15); m.putValue(20); //m.erase(0); //m.replace(2, 100); if (m.contains(11)){ printf("값을 포함하고 있습니다.\n"); } else { printf("포함하지 않습니다.\n"); } for (int i = 0; i < m.getCount(); i++) { printf(" %d ", m.getValue(i)); } return 0; } |
'C++' 카테고리의 다른 글
c++ 16 ( 파일 입출력 1 ) (0) | 2022.02.23 |
---|---|
c++ 15 ( 기본 자료구조 - STL 기초 자료구조 활용 ) (0) | 2022.02.23 |
c++ 13 ( const / static / extern ) (0) | 2022.02.19 |
c++ 12 (문자열과 네임스페이스 그리고 레퍼런스 타입) (0) | 2022.02.17 |
c++ 11 (실행구조 / Bitwise / 순수 가상함수) (0) | 2022.02.17 |