개발일지공부아이디어
    • 4월
    • 3월
    • 2월
    • 1월
  • 30

    26. 3. 30.

  • 27

    26. 3. 27.

  • 26

    26. 3. 26.

  • 25

    26. 3. 25.

  • 24

    26. 3. 24.

  • 23

    26. 3. 23.

  • 19

    26. 3. 19.

  • 18

    26. 3. 18.

  • 17

    26. 3. 17.

  • 16

    26. 3. 16.

  • 13

    26. 3. 13.

  • 2차 프로젝트 일지 - 6일차

    26. 3. 10.

  • 2차 프로젝트 일지 - 5일차

    26. 3. 9.

  • 09

    26. 3. 9.

  • 2차 프로젝트 일지 - 4일차

    26. 3. 8.

  • 2차 프로젝트 일지 - 3일차

    26. 3. 7.

  • 06

    26. 3. 6.

  • 2차 프로젝트 일지 - 2일차

    26. 3. 6.

  • 05

    26. 3. 5.

  • 2차 프로젝트 일지 - 1일차

    26. 3. 5.

  • C++ 기본기 연습 프로젝트: 아이템 사전 프로그램

    26. 3. 4.

  • 03

    26. 3. 3.

  • C++ 기본기 연습 프로젝트: 카드 덱 브라우저

    26. 3. 2.

로딩 중...

C++ 기본기 연습 프로젝트: 카드 덱 브라우저

2026. 3. 2.

1. 동적 배열(vector) 직접 구현

답지 안보고 작성한 답안:
#pragma oncetemplate<typename T>class Vector{public:	Vector(int _size = 5) : size(_size)	{		capacity = _size + _size / 2;		data = new T[capacity];	}	~Vector()	{		if (data)		{			delete[] data;			data = nullptr;		}	}	void Add(const T& item)	{		// 1. check capacity whether full or not		if (size == capacity)		{			// 2. if full expand capacity and move items to new container			capacity = capacity + capacity / 2;			T* newHouse = new T[capacity];			for (int i = 0; i < capacity; ++i)			{				newHouse[i] = std::move(data[i]);			}			delete data; // 힙에 있는 T배열은 어떻게 지움?			data = std::move(newHouse);		}				// 3. if not append on the tail		data[size + 1] = item;	}	void Delete(const T& item)	{		if (size == 0)			return;		// 1. find delete target recursively and delete it only once		int targetIndex = 0;		for (int i = 0; i < size; ++i)		{			if (data[i] == item)			{				targetIndex = i;				break;			}		}		if (targetIndex)		{			delete data[targetIndex];			// 2. move left ones forward			for (int j = targetIndex + 1; j < size; ++j)				data[j - 1] = std::move(data[j]);		}	}private:	int size, capacity;	T* data = nullptr;};

채점

  1. data는 T*로 잘 잡았음
private:	int size, capacity;	T* data = nullptr;
  1. size와 capacity 개념 혼동
    • 생성자에서 size가 아니라 capacity를 받아야 함
    Vector(int _size = 5) : size(_size){	capacity = _size + _size / 2;	data = new T[capacity];}
    • Add()에서 반복문을 capacity가 아니라 size까지만 복사해야함
    for (int i = 0; i < capacity; ++i){	newHouse[i] = std::move(data[i]);}
  2. 배열 포인터 핸들링이 미숙함
    • T타입 배열 원소 삭제와 배열 포인터 정리를 혼동하고 있음
    data = new T[capacity]; // 생성자에선 T[]로 동적할당...delete data; // 힙에 있는 T배열은 어떻게 지움?
  3. size 증감 누락
  4. 복사 생성자/대입 연산자 미구현(얕은 복사 위험)

보완

  • 생성자
Vector(size_t cap = 5)	: size_(0), capacity_(cap){	data = static_cast<T*>(::operator new(sizeof(T) * capacity_)); // raw memory만 확보(T 생성자 호출 x)}
  • Add를 push_back으로 변경
  • lvalue rvalue 오버로딩
  • 동적할당 대신 placement new 기법 활용(메모리 할당 o, 초기화 x)
void push_back(const T& value){	if (size_ >= capacity_)		reallocate(capacity_ + capacity_ / 2 + 1);	new (data + size_) T(value);  // placement new	++size_;}void push_back(T&& value){	if (size_ >= capacity_)		reallocate(capacity_ + capacity_ / 2 + 1);	new (data + size_) T(std::move(value));	++size_;}
  • std::vector와 유사하게 pop_back 추가
void pop_back(){	assert(size_ > 0);	--size_;	data[size_].~T();  // 직접 소멸}
  • 특정 원소 삭제도 STL 자료구조 반복자Iterator 인자로 구현
Iterator erase(Iterator it){	assert(size_ > 0);	size_t index = it - data;	data[index].~T();  // 제거 대상 소멸	for (size_t i = index; i < size_ - 1; ++i)	{		new (data + i) T(std::move(data[i + 1]));		data[i + 1].~T();	}	--size_;	return data + index;}

궁금증

  1. &var와 var.operator->()의 차이
0x1000 : var  		  └── ptr = 0x5000
  • &it : var의 주소
&var == '0x0000'
  • var.operator->(): var 객체 내부 원소(ptr) 주소
var.operator->() == '0x5000'
  1. 포인터끼리 덧셈 뺄셈은 바이트 단위로 결과가 나오지 않는다
int arr[5] = {10,20,30,40,50};    int* data = arr; // 0x1000, 10int* pos = &arr[2]; // 0x1008, 30pos - data // (0x1008 - 0x1000) / sizeof(int) = 8 / 4 = 2

3, ::operator new/delete는 생성자 호출 없이 메모리만 확보한다(placement new)

T* p = new T;::operator delete(p);  // ❌ destructor 안 불림T* p = static_cast<T*>(::operator new(sizeof(T)));  delete p; // ❌ 생성자 안 불렸는데 destructor 호출됨

2. C++ 스타일 파일 입출력 복습

void LoadCards(const std::string& filename, Vector<Card>& cards){	std::ifstream file(filename);	if (!file.is_open()) return;	std::string line;	std::getline(file, line); // 첫 줄 헤더 건너뛰기	while (std::getline(file, line))	{		std::stringstream ss(line);		std::string id_str, name, type, cost_str, rarity_str;		std::getline(ss, id_str, ',');		std::getline(ss, name, ',');		std::getline(ss, type, ',');		std::getline(ss, cost_str, ',');		std::getline(ss, rarity_str, ',');		int id = std::stoi(id_str);		int cost = std::stoi(cost_str);		int rarity = std::stoi(rarity_str);		cards.push_back(Card(id, name, type, cost, rarity));	}}
  • getline()의 첫번째 인자는 std::string이 아니라 std::istream&라는 것
  • file에서 getline()으로 잡아놓은 한 줄을 while 반복문 안에서 각 변수로 찢어주기

3. 콘솔(명령 프롬프트) 커스터마이즈 복습

inline void ColorText(Color foreground, Color background = BLACK){	int color = foreground + background * 16;	SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), color);}inline void PutCursorOnPosition(int x, int y){	COORD pos = { static_cast<short>(x), static_cast<short>(y) };	SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos);}
  • SetConsole~(GetStdHandle(STD_OUTPUT_HANDLE), ~) API 봐도봐도 안익숙해짐

4. 원형 순환 테크닉 복습

int main(){	Vector<Card> deck;	LoadCards("data.txt", deck);	int selected = 0;	while (true)	{		render(deck, selected, (selected - 2 + (int)deck.size()) % (int)deck.size());		int ch = _getch();		if (ch == 0xE0) {			ch = _getch();			if (ch == 72)				selected = (selected - 1 + deck.size()) % deck.size();			if (ch == 80)				selected = (selected + 1) % deck.size();		}		if (ch == 27 || ch == 113) break;	}}

위 gif처럼 100과 1을 이으려면

  • selected - offset + deck.size()를 deck.size()로 나머지 연산한 값을 offset으로 넣어주면 된다
왼쪽 화살표26오른쪽 화살표