11. 클래스와 동적 메모리 대입(2) - Queue (Feat. 초기자 리스트, In-Class 초기화)

WanJu Kim·2022년 12월 12일
0

C++

목록 보기
48/81

이번에는 Queue를 보자. Queue는 Stack처럼 추상화 데이터형이지만, 후입선출(LIFO)인 Stack과 달리, 먼저 들어온 데이터가 먼저 나가는 선입선출(FIFO : First in First out)을 따른다. 다음의 코드를 보자.

Queue.h
#pragma once
class Customer
{
private:
	long arrive;
	int processtime;
public:
	Customer() { arrive = processtime = 0; }
	void Set(long when);
	long when() const { return arrive; }
	int pTime() const { return processtime; }
};

typedef Customer Item;

class Queue
{
	struct Node
	{
		Item item;
		struct Node* next;
	};
	enum { Q_SIZE = 10 };
public:
	Queue(int qs = Q_SIZE);
	~Queue();

	bool isEmpty() const;
	bool isFull() const;
	bool enqueue(const Item & item);
	bool dequeue(Item & item);
	int queueCount() const;
private:
	Queue(const Queue& q) : qSize(0) {}
	Queue& operator=(const Queue& q) { return *this; }
	Node* front;	// 머리.
	Node* rear;	// 꼬리.
	int items;	// 현재 항목 수.
	const int qSize;	//최대 항목 수.
};


Queue.cpp
#include "Queue.h"
#include <iostream>

void Customer::Set(long when)
{
	processtime = std::rand() % 3 + 1;
	arrive = when;
}

Queue::Queue(int qs)
	:front(nullptr), rear(nullptr), items(0), qSize(qs)
{
}

Queue::~Queue()
{
	/*if (front == nullptr)
		return;

	Node* temp = front;
	Node* toDelete = front;
	while (temp->next)
	{
		toDelete = temp;
		temp = temp->next;
		delete toDelete;
	}
	delete toDelete;*/

	Node* temp;
	while (front != nullptr)
	{
		temp = front;
		front = front->next;
		delete temp;
	}
}

bool Queue::isEmpty() const
{
	/*if (items == 0)
		return true;
	return false;*/

	return items == 0;
}

bool Queue::isFull() const
{
	/*if (items == qSize)
		return true;
	return false;*/

	return items == qSize;
}

bool Queue::enqueue(const Item& item)
{
	/*if (isFull())
		return false;

	if (front == nullptr)
	{
		front = new Node();
		front->item = item;
	}
	else
	{
		Node* temp = front;
		while (temp->next)
		{
			temp = temp->next;
		}
		temp->next = new Node();
		temp->next->item = item;
		rear->item = item;
		rear->next = nullptr;
	}
	return true;*/

	if (isFull())
		return false;

	Node* add = new Node();
	std::bad_alloc exception;	// 예외를 던짐.
	add->item = item;
	add->next = nullptr;
	items++;
	if (front == nullptr)
		front = add;
	else
		rear->next = add;
	rear = add;
	return true;
}

bool Queue::dequeue(Item& item)
{
	/*if (isEmpty())
		return false;

	Node* temp = front;
	while (temp->next)
	{
		temp = temp->next;
	}
	temp->next = nullptr;
	delete rear;*/

	if (front == nullptr)
		return false;
	item = front->item;
	items--;
	Node* temp = front;
	front = front->next;
	delete temp;
	if (items == 0)
		rear = nullptr;

	return true;
}

int Queue::queueCount() const
{
	return items;
}

(주석 처리 한 건 필자가 짜본 매우 겸손한 코드다.)
이 코드에서 하나씩 보자.

초기자 리스트(initializer)

클래스 내의 const 변수에 주목해보자. const는 상수 특징을 가지고 있어서 생성과 동시에 초기화 시켜주어야 한다. 만약 이렇게 적었다면 제대로 작동하지 않는다.

Queue::Queue(int qs)
{
	...
	qSize = qs;	// 오류가 난다.
}

왜? 객체를 선언할 때 클래스 내의 변수들도 똑같이 선언된다고 생각하면 편하다. 그 후 생성자 코드 블록에서 하는 작업들은 대입 작업이다. const같은 변수들을 선언과 동시에 초기화시켜주기 위해서 생성자에 특별한 문법이 추가됐다. 이를 '초기자 리스트'라고 부른다. 혹은 이니셜라이저(initializer)라고 부른다. 이니셜라이저는 이런 식으로 작성한다.

Queue::Queue(int qs)
	:front(nullptr), rear(nullptr), items(0), qSize(qs)
{

}

이는 각각 괄호 왼쪽의 변수를 괄호 안의 변수로 '초기화'시켜달라는 의미이다. 오직 생성자에서만 가능하다. 클래스 내의 const뿐만 아니라 '참조 변수'들에 대해서는 초기자 리스트 문법을 반드시 사용해야 한다. 참조 변수들도 const와 마찬가지로 생성될 때만 초기화 될 수 있기 때문이다. 그리고 애초에 다른 기본 변수들도 시간 관점에서 이니셜라이저를 이용하는 게 좋다. 왜? 그렇지 않으면 디폴트 생성자를 대입 한 후에 다시 대입하는 거랑 같기 때문이다.

In-Class 초기화(보충)

이니셜라이저와 같은 효과를 가지는 문구는 다음과 같다.

class Queue
{
public:
	...
private:
	Node* front = nullptr;
	Node* rear = nullptr;
	int items = 0;
	const int qSize = Q_SIZE;
};

클래스 내에서 초기화 시키는 것이다. 그래서 이름도 In-Class 초기화다. 만약 이거랑 생성자랑 초기화 값이 다르면 어떻게 되는가? 생성자 값을 따른다. 그러니 효과는 동일하지만, 생성자가 약간 뒤늦게 실행 된다고 생각하면 편할 것 같다. 갠적으로 이거 궁금했는데 겨우 알았네;; 그래도 난 생성자를 사용할 것 같다. 생성자가 객체를 생성할 때 초기화를 담당하는 그런 뉘앙스가 강하기 때문이다.

그 외

복사 생성자와 대입 연산자를 private에 적음으로써 디폴트 정의들의 생성을 방지할 수 있고, 또 아예 사용하지 못하게 하는 효과가 있다.

std::bad_alloc exception; // 예외를 던짐.

동적 할당을 했을 때 아주 가끔씩 못 만드는 경우가 있다고 한다. 그런 예외적인 상황이 나오면 프로그램이 종료되는데 그런 걸 막아주는 문구인 것 같다. 찾아보니까 catch랑 쓰이는 것 같은데 정확한 쓰임새는 아직 잘 모르겠다;;

profile
Question, Think, Select

0개의 댓글