[CH2/03] 템플릿 및 STL

김여울·2025년 6월 9일
0

내일배움캠프

목록 보기
17/114

템플릿 및 STL

도전 기능은 어려워서 금요일 안에 할 수 있으면 추가 예정...

요구사항

필수 기능 가이드

  • 클래스의 이름은 SimpleVector라고 합니다.
  • 타입에 의존하지 않고 데이터를 받을수 있는 배열을 멤버변수로 갖습니다. → 타입에 의존 x = 템플릿
  • 생성자는 아래와 같이 구현 합니다.
    • 기본 생성자는 크기가 10인 배열을 만듭니다.
    • 숫자를 하나 받는 생성자는 해당 숫자에 해당되는 크기의 배열을 만듭니다.
  • 아래와 같은 멤버함수를 구현 합니다.
    • push_back 인자로 받은 원소를 맨 뒤에 추가 합니다. 반환값은 없습니다. 배열의 크기가 꽉 찼는데 원소가 더 들어올경우 아무 동작도 하지 않습니다.
    • pop_back은 벡터의 마지막 원소를 제거 합니다. 만약 제거할 원소가 없다면 아무 동작도 하지 않으며, 인자 및 반환값은 없습니다.
    • size는 인자가 없고 현재 원소의 개수를 반환합니다.
    • capacity 현재 내부 배열의 크기를 반환합니다.

➡ 템플릿 기반의 벡터 클래스 SimpleVector<T> 직접 구현
➡ 기본 생성자, 크기 지정 생성자, push_back, pop_back, size, capacity 등 멤버 함수 직접 작성

도전 기능 가이드

필수 기능을 모두 완료한 후, 아래 기능을 추가 합니다.

  • 복사 생성자를 구현 합니다. → 깊은 복사
  • 아래 멤버함수를 추가로 변경/구현 합니다.
    • push_back에서 배열의 크기가 꽉 찼는데 원소가 더 들어올경우, 기존 배열보다 크기를 5만큼 더 늘리고 새로운 원소까지 추가됩니다.(기존에 있던 값도 유지되야 합니다.)
    • resize는 정수 하나를 인자로 받습니다. 해당 정수가 현재 배열의 크기보다 작으면 아무 동작도 하지 않습니다. 만약 현재 배열보다 크기가 크면 해당 값만큼 크기를 재할당 합니다.(기존 원소는 그대로 있어야 합니다.)
    • sortData는 내부 데이터를 정렬하는 함수 입니다. 직접 정렬하지 않고 STL의 sort함수를 활용해서 정렬 합니다.



코드

#include <iostream>
using namespace std;

template < typename T>  // 타입에 의존하지 않음 -> 템플릿
class SimpleVector
{
private:
    T* data;
    int cap;
    int count;

public:
    // 기본 생성자 
    // count 전체 배열의 크기 : 10
    // cap 현재까지 넣은 데이터 개수 : 0 ~ cap
    SimpleVector() : cap(10), count(0)  // 생성 동시에 초기화
    {
        data = new T[cap];  // T 타입 배열 동적 메모리 할당
    }

    // 크기 지정 생성자
    SimpleVector(int capacity) : cap(capacity), count(0)
    {
        data = new T[cap];  // T 타입 배열 동적 메모리 할당
    }

    // 소멸자
    ~SimpleVector()
    {
        delete[] data;  // 동적 메모리 해제
    }

    // push_back
    void push_back(const T& value)  // 복사 없이 참조로 전달
    {
        if (count < cap)
        {
            data[count++] = value;  // 현재 count 위치에 값 저장 후 count 증가
        }
        else
        {
            // 용량 부족할 때 아무 동작 하지 않음 -> 예외 처리
            cout << "백터의 용량을 초과했습니다." << endl;
            return;

        }
    }

    // pop_back
    bool pop_back()
    {
        if (count > 0)
        {
            count--;  // 마지막 요소 제거
            return true;
        }
        else
        {
            // 제거할 원소 없으면 아무 동작 하지 않음 -> 예외 처리
            cout << "제거할 원소가 없습니다." << endl;
            return false;
        }
    }

    // size
    int size() const   // 읽기 전용 함수
    {
        return count;  // 현재 저장된 원소의 개수 반환
    }

    // capacity
    int capacity() const  // 읽기 전용 함수
    {
        return cap;  // 현재 현재 내부 배열의 크기 반환
    }
};

// main 함수
int main()
{
    SimpleVector<int> vec;  // 크기 지정하지 않은 경우 기본 크기 10으로 생성
    int choice;

    while (true)  // 조건 없이 무한 반복 루프 
    {
        cout << "1. 숫자 계속 입력하기\n";
        cout << "2. 마지막 숫자 제거하기\n";
        cout << "3. 현재 벡터의 상태 출력하기\n";
        cout << "0. 프로그램 종료하기\n";
        cout << "원하는 작업을 선택하세요: ";
        cin >> choice;
        cout << endl;

        if (choice == 0)  // 0 입력 시 종료
        {
            cout << "프로그램을 종료합니다." << endl;
            break;
        }
        else if (choice == 1)  // 숫자 입력
        {
            int element;
            while (true)
            {
                cout << "숫자를 입력하세요 (종료하려면 0 입력): ";
                cin >> element;

                if (element == 0)  // 0 입력 시 숫자 입력 종료
                {
                    cout << "숫자 입력을 종료합니다." << endl;
                    break;
                }
                vec.push_back(element);  // 입력된 숫자를 벡터에 추가
            }
            cout << endl;
        }
        else if (choice == 2)  // 마지막  숫자 제거
        {
            bool isPop = vec.pop_back();
            
            if (isPop)
            {
                cout << "마지막 숫자를 제거했습니다." << endl;
                cout << endl;
            }
        }

        else if (choice == 3)  // 현재 벡터 상태 출력
        {
            cout << "현재 벡터의 크기: " << vec.size() << endl;  // 현재 벡터의 크기 출력
            cout << "현재 벡터의 용량: " << vec.capacity() << endl;  // 현재 벡터의 용량 출력
        }
        else
        {
            cout << "잘못된 선택입니다. 다른 숫자를 입력해 주세요." << endl;  // 잘못된 선택 -> 예외 처리
        }

        cout << endl;
    }

    return 0;
}

구현 기능 정리

함수/기능설명
SimpleVector()기본 생성자 (크기 10 고정)
SimpleVector(int capacity)크기 지정 생성자
~SimpleVector()소멸자 (동적 메모리 해제)
void push_back(const T& element)값 추가 (꽉 차면 무시)
void pop_back()마지막 값 제거 (없으면 무시)
int size() const현재 들어있는 원소 개수
int capacity() const벡터의 전체 용량

멤버 초기화 리스트

// 기본 구조

클래스이름(매개변수들)  
    : 멤버변수1(1), 멤버변수2(2), ...  
{
    // 생성자 본문
}


 SimpleVector() : cap(10), count(0)  // 멤버 초기화 리스트
 {
     data = new T[cap];  // T 타입 배열 동적 메모리 할당
 }
이유설명
성능생성자 본문에서 대입하는 것보다 빠름
필수const, 참조(&) 멤버는 무조건 초기화 리스트 필요
가독성명확하고 직관적으로 보임

동적 배열 생성

  • data = new T[cap];
    • T 타입 배열을 동적으로 생성함
    • cap 크기만큼 new로 힙에 메모리 할당
    • 반드시 소멸자에서 delete[]로 해제 필요

크기 지정 생성자

 SimpleVector(int capacity) : cap(capacity), count(0)
 {
     data = new T[cap];  // T 타입 배열 동적 메모리 할당
 }
  • SimpleVector(int capacity) 생성자의 역할
    • 사용자가 직접 벡터의 크기를 지정할 수 있게 해주는 역할
    • capacity 는 배열의 초기 크기를 결정하는 파라미터
      • 벡터가 처음에 할당할 배열의 크기를 사용자가 지정할 수 있음
  • cap(capacity), count(0)
    • 생성자 초기화 리스트
    • 벡터의 용량을 지정하고 원소 개수는 0으로 초기화


const 참조

  • push_back(const T& value)
    • 복사 비용 줄이기 + 원본 보호
      → 큰 타입일 때 성능상 유리

count와 capacity 차이

  • count = 현재 들어있는 원소 개수
  • capacity = 전체 배열의 용량(최대 저장 개수)

size()와 capacity() → int?

  • 값을 return하니까 반환형 필요
  • void면 return 불가 → 컴파일 에러

if, while 같이 써도 되는지?

  • 다른 스코프니까 가능
  • if (choice == 1) 안에 while (true) 루프를 써서
    0 입력하면 빠져나오게 구성함

오류

문제
pop_back()에서 원소가 없을 때도 "마지막 숫자를 제거했습니다." 메시지가 출력된다

원인

void pop_back() 
{
    if (count > 0)
    {
        count--;  // 마지막 요소 제거
    }
    else
    {
        // 제거할 원소 없으면 아무 동작 하지 않음 -> 예외 처리
        cout << "제거할 원소가 없습니다." << endl;
        return;
    }
}

/.../

int main()
{
	else if (choice == 2)  // 마지막  숫자 제거
	{
    vec.pop_back();
    cout << "마지막 숫자를 제거했습니다." << endl;
	}
}

main 함수에서 pop_back 실행되고 "마지막 숫자를 제거했습니다." 출력함
→ 제거할 숫자 없어도 계속 출력됨

해결

 bool pop_back()
 {
     if (count > 0)
     {
         count--;  // 마지막 요소 제거
         return true;
     }
     else
     {
         // 제거할 원소 없으면 아무 동작 하지 않음 -> 예외 처리
         cout << "제거할 원소가 없습니다." << endl;
         return false;
     }
 }
 
 
 int main()
 {
 	else if (choice == 2)  // 마지막  숫자 제거
	{
    bool isPop = vec.pop_back();

    	if (isPop)
    	{
        cout << "마지막 숫자를 제거했습니다." << endl;
        cout << endl;
    	}
	}
 }

pop_back() 을 bool 타입으로 바꾸고 요소가 남아있으면 true로, 없으면 false로 만든다.
그리고 main() 함수에서 pop_back()을 isPop으로 받고 if로 isPop이 참일 때만 "마지막 숫자 제거 ~ " 를 출력한다.

2개의 댓글

comment-user-thumbnail
2025년 6월 9일

🫡

1개의 답글