챕터7. 실습 문제
2025. 3. 28. 08:52ㆍProgramming Languages/C++
7.6 실습 문제
문제 1: 범용 스마트 배열 템플릿
다양한 타입에 대해 동작하는 동적 배열 클래스를 구현하세요:
#include <iostream>
#include <stdexcept>
#include <initializer_list>
template <typename T>
class SmartArray {
private:
T* data;
size_t size;
size_t capacity;
// 용량 확장
void expand(size_t newCapacity) {
if (newCapacity <= capacity) return;
T* newData = new T[newCapacity];
// 기존 데이터 복사
for (size_t i = 0; i < size; i++) {
newData[i] = data[i];
}
// 기존 메모리 해제
delete[] data;
// 새 데이터로 교체
data = newData;
capacity = newCapacity;
}
public:
// 기본 생성자
SmartArray() : data(nullptr), size(0), capacity(0) {}
// 크기 지정 생성자
explicit SmartArray(size_t initialSize) : size(initialSize), capacity(initialSize) {
data = new T[capacity];
// 기본값으로 초기화
for (size_t i = 0; i < size; i++) {
data[i] = T();
}
}
// 초기화 리스트 생성자
SmartArray(std::initializer_list<T> init) : size(init.size()), capacity(init.size()) {
data = new T[capacity];
// 초기화 리스트의 값으로 배열 초기화
size_t i = 0;
for (const T& val : init) {
data[i++] = val;
}
}
// 복사 생성자
SmartArray(const SmartArray& other) : size(other.size), capacity(other.capacity) {
data = new T[capacity];
// 다른 배열의 데이터 복사
for (size_t i = 0; i < size; i++) {
data[i] = other.data[i];
}
}
// 이동 생성자
SmartArray(SmartArray&& other) noexcept : data(other.data), size(other.size), capacity(other.capacity) {
other.data = nullptr;
other.size = 0;
other.capacity = 0;
}
// 소멸자
~SmartArray() {
delete[] data;
}
// 복사 대입 연산자
SmartArray& operator=(const SmartArray& other) {
if (this != &other) {
// 기존 메모리 해제
delete[] data;
// 새 메모리 할당
size = other.size;
capacity = other.capacity;
data = new T[capacity];
// 데이터 복사
for (size_t i = 0; i < size; i++) {
data[i] = other.data[i];
}
}
return *this;
}
// 이동 대입 연산자
SmartArray& operator=(SmartArray&& other) noexcept {
if (this != &other) {
// 기존 메모리 해제
delete[] data;
// 리소스 이동
data = other.data;
size = other.size;
capacity = other.capacity;
// 원본 무효화
other.data = nullptr;
other.size = 0;
other.capacity = 0;
}
return *this;
}
// 요소 접근 연산자
T& operator[](size_t index) {
if (index >= size) {
throw std::out_of_range("인덱스가 범위를 벗어났습니다.");
}
return data[index];
}
const T& operator[](size_t index) const {
if (index >= size) {
throw std::out_of_range("인덱스가 범위를 벗어났습니다.");
}
return data[index];
}
// 배열 뒤에 새 요소 추가
void push_back(const T& value) {
if (size >= capacity) {
// 용량이 부족하면 두 배로 확장
expand(capacity == 0 ? 1 : capacity * 2);
}
data[size++] = value;
}
// 배열 뒤의 요소 제거
void pop_back() {
if (size > 0) {
--size;
}
}
// 지정된 위치에 요소 삽입
void insert(size_t index, const T& value) {
if (index > size) {
throw std::out_of_range("삽입 위치가 유효하지 않습니다.");
}
// 용량이 부족하면 확장
if (size >= capacity) {
expand(capacity == 0 ? 1 : capacity * 2);
}
// 요소 이동
for (size_t i = size; i > index; --i) {
data[i] = data[i - 1];
}
// 새 요소 삽입
data[index] = value;
++size;
}
// 지정된 위치의 요소 제거
void erase(size_t index) {
if (index >= size) {
throw std::out_of_range("삭제 위치가 유효하지 않습니다.");
}
// 요소 이동
for (size_t i = index; i < size - 1; ++i) {
data[i] = data[i + 1];
}
--size;
}
// 배열 크기 반환
size_t getSize() const {
return size;
}
// 배열 용량 반환
size_t getCapacity() const {
return capacity;
}
// 배열이 비어 있는지 확인
bool isEmpty() const {
return size == 0;
}
// 배열 내용 출력
void print() const {
std::cout << "[ ";
for (size_t i = 0; i < size; ++i) {
std::cout << data[i];
if (i < size - 1) {
std::cout << ", ";
}
}
std::cout << " ]" << std::endl;
}
};
int main() {
// 정수 배열 테스트
SmartArray<int> intArray = {10, 20, 30, 40, 50};
std::cout << "초기 정수 배열:" << std::endl;
intArray.print();
// 요소 추가
intArray.push_back(60);
intArray.push_back(70);
std::cout << "요소 추가 후:" << std::endl;
intArray.print();
// 요소 삽입
intArray.insert(2, 25);
std::cout << "인덱스 2에 25 삽입 후:" << std::endl;
intArray.print();
// 요소 삭제
intArray.erase(4);
std::cout << "인덱스 4의 요소 삭제 후:" << std::endl;
intArray.print();
// 복사 생성자 테스트
SmartArray<int> intArrayCopy = intArray;
std::cout << "복사 생성된 배열:" << std::endl;
intArrayCopy.print();
// 원본 배열 변경
intArray[0] = 100;
std::cout << "원본 배열(변경 후):" << std::endl;
intArray.print();
std::cout << "복사된 배열(원본과 독립적):" << std::endl;
intArrayCopy.print();
// 문자열 배열 테스트
SmartArray<std::string> stringArray;
stringArray.push_back("Hello");
stringArray.push_back("World");
stringArray.push_back("C++");
stringArray.push_back("Templates");
std::cout << "\n문자열 배열:" << std::endl;
stringArray.print();
return 0;
}
문제 2: 함수 템플릿을 사용한 알고리즘 라이브러리 구현
다양한 타입의 배열과 컨테이너에서 사용할 수 있는 알고리즘 함수 템플릿 모음을 구현하세요:
#include <iostream>
#include <vector>
#include <list>
#include <string>
#include <type_traits>
// 배열의 모든 요소 출력
template <typename Container>
void printAll(const Container& container, const std::string& label = "컨테이너 내용") {
std::cout << label << ": ";
// 범위 기반 for 루프로 모든 요소 출력
for (const auto& item : container) {
std::cout << item << " ";
}
std::cout << std::endl;
}
// 배열에서 최댓값 찾기
template <typename Container>
auto findMax(const Container& container) -> typename std::remove_reference<decltype(*std::begin(container))>::type {
if (std::begin(container) == std::end(container)) {
throw std::runtime_error("빈 컨테이너에서 최댓값을 찾을 수 없습니다.");
}
auto maxElement = *std::begin(container);
for (const auto& item : container) {
if (item > maxElement) {
maxElement = item;
}
}
return maxElement;
}
// 배열에서 최솟값 찾기
template <typename Container>
auto findMin(const Container& container) -> typename std::remove_reference<decltype(*std::begin(container))>::type {
if (std::begin(container) == std::end(container)) {
throw std::runtime_error("빈 컨테이너에서 최솟값을 찾을 수 없습니다.");
}
auto minElement = *std::begin(container);
for (const auto& item : container) {
if (item < minElement) {
minElement = item;
}
}
return minElement;
}
// 배열 요소의 합계 계산
template <typename Container>
auto sum(const Container& container) -> typename std::remove_reference<decltype(*std::begin(container))>::type {
if (std::begin(container) == std::end(container)) {
return typename std::remove_reference<decltype(*std::begin(container))>::type();
}
auto total = *std::begin(container);
auto it = std::begin(container);
// 첫 번째 요소는 이미 처리했으므로 다음 요소부터 시작
++it;
for (; it != std::end(container); ++it) {
total += *it;
}
return total;
}
// 배열 요소의 평균 계산
template <typename Container>
double average(const Container& container) {
if (std::begin(container) == std::end(container)) {
throw std::runtime_error("빈 컨테이너에서 평균을 계산할 수 없습니다.");
}
// 합계 계산
auto total = sum(container);
// 요소 개수 계산
size_t count = 0;
for (auto it = std::begin(container); it != std::end(container); ++it) {
++count;
}
// 평균 반환
return static_cast<double>(total) / count;
}
// 조건에 맞는 요소 개수 세기
template <typename Container, typename Predicate>
size_t countIf(const Container& container, Predicate pred) {
size_t count = 0;
for (const auto& item : container) {
if (pred(item)) {
++count;
}
}
return count;
}
// 조건에 맞는 요소로 새 컨테이너 만들기
template <typename Container, typename Predicate>
Container filter(const Container& container, Predicate pred) {
Container result;
for (const auto& item : container) {
if (pred(item)) {
result.insert(std::end(result), item);
}
}
return result;
}
// 각 요소에 함수 적용하여 새 컨테이너 만들기
template <typename Container, typename Function>
auto map(const Container& container, Function func) -> Container {
Container result;
for (const auto& item : container) {
result.insert(std::end(result), func(item));
}
return result;
}
int main() {
// 벡터 테스트
std::vector<int> numbers = {5, 2, 9, 1, 7, 6, 3, 8, 4};
std::cout << "=== 벡터 테스트 ===" << std::endl;
printAll(numbers, "원본 숫자");
std::cout << "최댓값: " << findMax(numbers) << std::endl;
std::cout << "최솟값: " << findMin(numbers) << std::endl;
std::cout << "합계: " << sum(numbers) << std::endl;
std::cout << "평균: " << average(numbers) << std::endl;
// 5보다 큰 숫자 개수
auto greaterThan5 = [](int n) { return n > 5; };
std::cout << "5보다 큰 숫자 개수: " << countIf(numbers, greaterThan5) << std::endl;
// 짝수만 필터링
auto isEven = [](int n) { return n % 2 == 0; };
std::vector<int> evenNumbers = filter(numbers, isEven);
printAll(evenNumbers, "짝수만");
// 각 숫자 제곱
auto square = [](int n) { return n * n; };
std::vector<int> squaredNumbers = map(numbers, square);
printAll(squaredNumbers, "제곱 결과");
// 리스트 테스트
std::list<double> prices = {10.5, 25.3, 5.7, 35.9, 15.2};
std::cout << "\n=== 리스트 테스트 ===" << std::endl;
printAll(prices, "원본 가격");
std::cout << "최고 가격: " << findMax(prices) << std::endl;
std::cout << "최저 가격: " << findMin(prices) << std::endl;
std::cout << "총 가격: " << sum(prices) << std::endl;
std::cout << "평균 가격: " << average(prices) << std::endl;
// 20불 이상인 가격 필터링
auto over20 = [](double p) { return p >= 20.0; };
std::list<double> highPrices = filter(prices, over20);
printAll(highPrices, "20불 이상 가격");
// 각 가격에 10% 세금 추가
auto addTax = [](double p) { return p * 1.1; };
std::list<double> pricesWithTax = map(prices, addTax);
printAll(pricesWithTax, "세금 추가 가격");
// 문자열 테스트
std::vector<std::string> names = {"Alice", "Bob", "Charlie", "David", "Eva"};
std::cout << "\n=== 문자열 테스트 ===" << std::endl;
printAll(names, "이름 목록");
// 이름 길이가 5 이상인 것 필터링
auto longName = [](const std::string& s) { return s.length() >= 5; };
std::vector<std::string> longNames = filter(names, longName);
printAll(longNames, "긴 이름 (5자 이상)");
// 이름을 모두 대문자로 변환
auto toUpper = [](std::string s) {
for (char& c : s) {
c = std::toupper(c);
}
return s;
};
std::vector<std::string> upperNames = map(names, toUpper);
printAll(upperNames, "대문자 이름");
return 0;
}
'Programming Languages > C++' 카테고리의 다른 글
STL 컨테이너 (0) | 2025.03.28 |
---|---|
STL (Standard Template Library) (0) | 2025.03.28 |
템플릿 메타프로그래밍 (0) | 2025.03.28 |
가변 템플릿(Variadic Templates) (C++11) (0) | 2025.03.28 |
비타입 템플릿 매개변수 (0) | 2025.03.28 |