모던 C++ (C++11/14/17/20)
모던 C++ (C++11/14/17/20)¶
1. C++ 버전 변화¶
┌─────────────────────────────────────────────────────────────┐
│ C++ 표준 발전 역사 │
├─────────────────────────────────────────────────────────────┤
│ 1998 2003 2011 2014 2017 2020 2023 │
│ │ │ │ │ │ │ │ │
│ ▼ ▼ ▼ ▼ ▼ ▼ ▼ │
│ C++98 C++03 C++11 C++14 C++17 C++20 C++23 │
│ (버그 (대규모 (개선) (대규모 (대규모 │
│ 수정) 업데이트) 업데이트) 업데이트) │
└─────────────────────────────────────────────────────────────┘
컴파일 옵션¶
# C++11
g++ -std=c++11 main.cpp -o main
# C++14
g++ -std=c++14 main.cpp -o main
# C++17
g++ -std=c++17 main.cpp -o main
# C++20
g++ -std=c++20 main.cpp -o main
2. C++11 주요 기능¶
auto 키워드¶
#include <iostream>
#include <vector>
#include <map>
int main() {
// 타입 자동 추론
auto x = 42; // int
auto y = 3.14; // double
auto s = "Hello"; // const char*
std::vector<int> vec = {1, 2, 3, 4, 5};
// 긴 타입명 대신 auto 사용
auto it = vec.begin(); // std::vector<int>::iterator
std::map<std::string, int> ages = {
{"Alice", 25},
{"Bob", 30}
};
// 복잡한 타입도 auto로 간단히
for (auto& pair : ages) {
std::cout << pair.first << ": " << pair.second << std::endl;
}
// 함수 반환 타입 추론
auto add = [](int a, int b) { return a + b; };
std::cout << add(3, 4) << std::endl; // 7
return 0;
}
범위 기반 for 루프¶
#include <iostream>
#include <vector>
#include <array>
int main() {
std::vector<int> vec = {1, 2, 3, 4, 5};
// 값 복사
for (int x : vec) {
std::cout << x << " ";
}
std::cout << std::endl;
// 참조 (수정 가능)
for (int& x : vec) {
x *= 2;
}
// const 참조 (읽기만)
for (const int& x : vec) {
std::cout << x << " ";
}
std::cout << std::endl;
// 배열에도 사용 가능
int arr[] = {10, 20, 30};
for (int x : arr) {
std::cout << x << " ";
}
std::cout << std::endl;
// 초기화 리스트와 함께
for (int x : {100, 200, 300}) {
std::cout << x << " ";
}
std::cout << std::endl;
return 0;
}
nullptr¶
#include <iostream>
void foo(int n) {
std::cout << "int: " << n << std::endl;
}
void foo(int* p) {
std::cout << "pointer" << std::endl;
}
int main() {
// C++11 이전: NULL은 0으로 정의됨
// foo(NULL); // 모호함!
// C++11: nullptr 사용
foo(nullptr); // pointer
foo(0); // int: 0
int* p = nullptr;
if (p == nullptr) {
std::cout << "p is null" << std::endl;
}
return 0;
}
초기화 리스트 (Initializer List)¶
#include <iostream>
#include <vector>
#include <map>
#include <initializer_list>
class MyContainer {
private:
std::vector<int> data;
public:
MyContainer(std::initializer_list<int> list)
: data(list) {
std::cout << "생성자 호출" << std::endl;
}
void print() const {
for (int x : data) {
std::cout << x << " ";
}
std::cout << std::endl;
}
};
int main() {
// 균일 초기화 (Uniform Initialization)
int a{42};
double b{3.14};
std::string c{"Hello"};
// 컨테이너 초기화
std::vector<int> vec = {1, 2, 3, 4, 5};
std::map<std::string, int> ages = {
{"Alice", 25},
{"Bob", 30}
};
// 커스텀 클래스
MyContainer mc = {10, 20, 30, 40};
mc.print(); // 10 20 30 40
// 배열
int arr[] = {1, 2, 3};
// 중괄호로 narrowing 방지
// int x{3.14}; // 에러! narrowing conversion
return 0;
}
람다 표현식¶
#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>
int main() {
// 기본 람다
auto hello = []() {
std::cout << "Hello, Lambda!" << std::endl;
};
hello();
// 매개변수와 반환
auto add = [](int a, int b) -> int {
return a + b;
};
std::cout << add(3, 4) << std::endl; // 7
// 캡처 (외부 변수 접근)
int x = 10;
int y = 20;
// 값 캡처
auto byValue = [x, y]() {
std::cout << x + y << std::endl;
};
// 참조 캡처
auto byRef = [&x, &y]() {
x++;
y++;
};
// 모든 변수 값 캡처
auto allByValue = [=]() {
std::cout << x + y << std::endl;
};
// 모든 변수 참조 캡처
auto allByRef = [&]() {
x = 100;
y = 200;
};
// 혼합 캡처
auto mixed = [=, &x]() { // y는 값, x는 참조
x = 50;
std::cout << y << std::endl;
};
// STL 알고리즘과 사용
std::vector<int> vec = {3, 1, 4, 1, 5, 9, 2, 6};
// 정렬
std::sort(vec.begin(), vec.end(),
[](int a, int b) { return a > b; }); // 내림차순
// 출력
std::for_each(vec.begin(), vec.end(),
[](int x) { std::cout << x << " "; });
std::cout << std::endl;
return 0;
}
이동 시맨틱 (Move Semantics)¶
#include <iostream>
#include <string>
#include <vector>
#include <utility>
class Buffer {
private:
int* data;
size_t size;
public:
// 생성자
Buffer(size_t n) : data(new int[n]), size(n) {
std::cout << "생성자" << std::endl;
}
// 소멸자
~Buffer() {
delete[] data;
std::cout << "소멸자" << std::endl;
}
// 복사 생성자
Buffer(const Buffer& other)
: data(new int[other.size]), size(other.size) {
std::copy(other.data, other.data + size, data);
std::cout << "복사 생성자" << std::endl;
}
// 이동 생성자 (C++11)
Buffer(Buffer&& other) noexcept
: data(other.data), size(other.size) {
other.data = nullptr;
other.size = 0;
std::cout << "이동 생성자" << std::endl;
}
// 복사 대입 연산자
Buffer& operator=(const Buffer& other) {
if (this != &other) {
delete[] data;
size = other.size;
data = new int[size];
std::copy(other.data, other.data + size, data);
}
std::cout << "복사 대입" << std::endl;
return *this;
}
// 이동 대입 연산자 (C++11)
Buffer& operator=(Buffer&& other) noexcept {
if (this != &other) {
delete[] data;
data = other.data;
size = other.size;
other.data = nullptr;
other.size = 0;
}
std::cout << "이동 대입" << std::endl;
return *this;
}
};
Buffer createBuffer() {
return Buffer(100); // 이동 최적화
}
int main() {
Buffer b1(10);
Buffer b2 = b1; // 복사 생성자
Buffer b3 = std::move(b1); // 이동 생성자
// b1은 이제 빈 상태
Buffer b4 = createBuffer(); // 이동 생성자 (RVO로 생략될 수 있음)
return 0;
}
스마트 포인터¶
#include <iostream>
#include <memory>
class Resource {
public:
Resource() { std::cout << "생성" << std::endl; }
~Resource() { std::cout << "소멸" << std::endl; }
};
int main() {
// unique_ptr: 단독 소유
std::unique_ptr<Resource> p1(new Resource());
auto p2 = std::make_unique<Resource>(); // C++14
// shared_ptr: 공유 소유
auto p3 = std::make_shared<Resource>();
auto p4 = p3; // 참조 카운트 증가
std::cout << "참조 카운트: " << p3.use_count() << std::endl;
// weak_ptr: 약한 참조
std::weak_ptr<Resource> weak = p3;
if (auto sp = weak.lock()) {
std::cout << "객체 접근 가능" << std::endl;
}
return 0;
}
constexpr¶
#include <iostream>
#include <array>
// 컴파일 타임 상수 함수
constexpr int factorial(int n) {
return (n <= 1) ? 1 : n * factorial(n - 1);
}
constexpr int square(int x) {
return x * x;
}
// 컴파일 타임 상수 클래스
class Point {
public:
int x, y;
constexpr Point(int x, int y) : x(x), y(y) {}
constexpr int getX() const { return x; }
constexpr int getY() const { return y; }
};
int main() {
// 컴파일 타임에 계산
constexpr int fact5 = factorial(5); // 120
constexpr int sq10 = square(10); // 100
// 배열 크기로 사용 가능
std::array<int, factorial(4)> arr; // 크기 24
// 컴파일 타임 상수 객체
constexpr Point p(3, 4);
static_assert(p.getX() == 3, "X should be 3");
std::cout << "5! = " << fact5 << std::endl;
std::cout << "10^2 = " << sq10 << std::endl;
return 0;
}
3. C++14 주요 기능¶
제네릭 람다¶
#include <iostream>
#include <vector>
#include <string>
int main() {
// C++14: auto 매개변수
auto print = [](auto x) {
std::cout << x << std::endl;
};
print(42); // int
print(3.14); // double
print("Hello"); // const char*
// 여러 타입 매개변수
auto add = [](auto a, auto b) {
return a + b;
};
std::cout << add(1, 2) << std::endl; // 3
std::cout << add(1.5, 2.5) << std::endl; // 4
std::cout << add(std::string("Hello, "), std::string("World!")) << std::endl;
return 0;
}
변수 템플릿¶
#include <iostream>
// 변수 템플릿 (C++14)
template<typename T>
constexpr T pi = T(3.141592653589793238462643383);
template<typename T>
constexpr T e = T(2.718281828459045235360287471);
int main() {
std::cout << "float pi: " << pi<float> << std::endl;
std::cout << "double pi: " << pi<double> << std::endl;
std::cout << "double e: " << e<double> << std::endl;
return 0;
}
[[deprecated]] 속성¶
#include <iostream>
// 함수 사용 중단 경고
[[deprecated("Use newFunction() instead")]]
void oldFunction() {
std::cout << "Old function" << std::endl;
}
void newFunction() {
std::cout << "New function" << std::endl;
}
// 클래스도 가능
class [[deprecated("Use NewClass instead")]] OldClass {};
int main() {
// oldFunction(); // 컴파일러 경고 발생
newFunction();
return 0;
}
이진 리터럴과 자릿수 구분자¶
#include <iostream>
int main() {
// 이진 리터럴 (C++14)
int binary = 0b1010'1010; // 170
int hex = 0xFF'FF; // 65535
// 자릿수 구분자
int million = 1'000'000;
double pi = 3.141'592'653;
int binary2 = 0b1111'0000'1111'0000;
std::cout << "binary: " << binary << std::endl;
std::cout << "million: " << million << std::endl;
std::cout << "pi: " << pi << std::endl;
return 0;
}
반환 타입 추론¶
#include <iostream>
#include <vector>
// C++14: 반환 타입 자동 추론
auto multiply(int a, int b) {
return a * b; // int 반환으로 추론
}
auto getString() {
return std::string("Hello"); // std::string 반환으로 추론
}
// 재귀에도 사용 가능
auto factorial(int n) -> int { // 재귀는 명시 필요
return (n <= 1) ? 1 : n * factorial(n - 1);
}
int main() {
auto result = multiply(3, 4);
std::cout << result << std::endl; // 12
auto str = getString();
std::cout << str << std::endl; // Hello
return 0;
}
4. C++17 주요 기능¶
구조적 바인딩¶
#include <iostream>
#include <tuple>
#include <map>
#include <array>
std::tuple<int, double, std::string> getData() {
return {42, 3.14, "Hello"};
}
int main() {
// 튜플 분해
auto [num, pi, str] = getData();
std::cout << num << ", " << pi << ", " << str << std::endl;
// pair 분해
std::pair<int, std::string> p = {1, "Alice"};
auto [id, name] = p;
std::cout << id << ": " << name << std::endl;
// 배열 분해
int arr[] = {1, 2, 3};
auto [a, b, c] = arr;
std::cout << a << ", " << b << ", " << c << std::endl;
// map 순회
std::map<std::string, int> ages = {
{"Alice", 25},
{"Bob", 30}
};
for (auto& [name, age] : ages) {
std::cout << name << ": " << age << std::endl;
}
// 구조체 분해
struct Point { int x, y; };
Point pt = {10, 20};
auto [x, y] = pt;
std::cout << "Point: " << x << ", " << y << std::endl;
return 0;
}
if/switch 초기화 구문¶
#include <iostream>
#include <map>
#include <mutex>
std::map<int, std::string> database = {
{1, "Alice"},
{2, "Bob"}
};
std::mutex mtx;
int main() {
// if with initializer
if (auto it = database.find(1); it != database.end()) {
std::cout << "Found: " << it->second << std::endl;
}
// switch with initializer
switch (auto x = 2 * 3; x) {
case 6:
std::cout << "x is 6" << std::endl;
break;
default:
std::cout << "x is " << x << std::endl;
}
// lock과 함께 사용
if (std::lock_guard<std::mutex> lock(mtx); true) {
// 뮤텍스 잠금 상태에서 작업
std::cout << "Protected section" << std::endl;
}
return 0;
}
if constexpr¶
#include <iostream>
#include <type_traits>
#include <string>
template<typename T>
void process(T value) {
if constexpr (std::is_integral_v<T>) {
std::cout << "정수: " << value * 2 << std::endl;
} else if constexpr (std::is_floating_point_v<T>) {
std::cout << "실수: " << value / 2 << std::endl;
} else if constexpr (std::is_same_v<T, std::string>) {
std::cout << "문자열: " << value.length() << "글자" << std::endl;
} else {
std::cout << "기타: " << value << std::endl;
}
}
int main() {
process(10); // 정수: 20
process(3.14); // 실수: 1.57
process(std::string("Hello")); // 문자열: 5글자
process("Hello"); // 기타: Hello
return 0;
}
std::optional¶
#include <iostream>
#include <optional>
#include <string>
std::optional<int> divide(int a, int b) {
if (b == 0) {
return std::nullopt;
}
return a / b;
}
std::optional<std::string> findUser(int id) {
if (id == 1) return "Alice";
if (id == 2) return "Bob";
return std::nullopt;
}
int main() {
// 기본 사용
auto result = divide(10, 2);
if (result) {
std::cout << "결과: " << *result << std::endl;
}
auto result2 = divide(10, 0);
std::cout << "has_value: " << result2.has_value() << std::endl; // 0
// value_or로 기본값 제공
std::cout << divide(10, 3).value_or(-1) << std::endl; // 3
std::cout << divide(10, 0).value_or(-1) << std::endl; // -1
// 문자열
auto user = findUser(1);
if (user) {
std::cout << "User: " << *user << std::endl;
}
std::cout << findUser(3).value_or("Unknown") << std::endl; // Unknown
return 0;
}
std::variant¶
#include <iostream>
#include <variant>
#include <string>
int main() {
// 여러 타입 중 하나를 저장
std::variant<int, double, std::string> v;
v = 42;
std::cout << std::get<int>(v) << std::endl;
v = 3.14;
std::cout << std::get<double>(v) << std::endl;
v = "Hello";
std::cout << std::get<std::string>(v) << std::endl;
// 현재 타입 확인
if (std::holds_alternative<std::string>(v)) {
std::cout << "문자열입니다" << std::endl;
}
// 인덱스로 접근
std::cout << "index: " << v.index() << std::endl; // 2
// visit 패턴
std::variant<int, double, std::string> values[] = {
42, 3.14, std::string("Hello")
};
for (auto& val : values) {
std::visit([](auto&& arg) {
std::cout << arg << std::endl;
}, val);
}
return 0;
}
std::filesystem¶
#include <iostream>
#include <filesystem>
namespace fs = std::filesystem;
int main() {
// 경로 다루기
fs::path p = "/home/user/documents/file.txt";
std::cout << "filename: " << p.filename() << std::endl;
std::cout << "stem: " << p.stem() << std::endl;
std::cout << "extension: " << p.extension() << std::endl;
std::cout << "parent_path: " << p.parent_path() << std::endl;
// 현재 디렉토리
std::cout << "현재 경로: " << fs::current_path() << std::endl;
// 파일/디렉토리 존재 확인
fs::path testPath = ".";
if (fs::exists(testPath)) {
std::cout << testPath << " 존재함" << std::endl;
}
// 디렉토리 순회
std::cout << "\n=== 현재 디렉토리 내용 ===" << std::endl;
for (const auto& entry : fs::directory_iterator(".")) {
std::cout << entry.path().filename();
if (fs::is_directory(entry)) {
std::cout << " [DIR]";
} else {
std::cout << " [" << fs::file_size(entry) << " bytes]";
}
std::cout << std::endl;
}
// 경로 조합
fs::path dir = "/home/user";
fs::path file = "document.txt";
fs::path full = dir / file;
std::cout << "조합된 경로: " << full << std::endl;
return 0;
}
std::string_view¶
#include <iostream>
#include <string>
#include <string_view>
// 문자열을 복사하지 않고 참조
void printView(std::string_view sv) {
std::cout << "View: " << sv << std::endl;
std::cout << "Length: " << sv.length() << std::endl;
}
int main() {
// 다양한 문자열 타입에서 생성
std::string str = "Hello, World!";
const char* cstr = "Hello from C!";
char arr[] = "Hello from array!";
printView(str);
printView(cstr);
printView(arr);
printView("Literal string");
// 서브스트링 (복사 없음)
std::string_view sv = "Hello, World!";
std::string_view sub = sv.substr(0, 5);
std::cout << "Substring: " << sub << std::endl; // Hello
// 주의: 원본이 사라지면 댕글링!
// std::string_view bad;
// {
// std::string temp = "temporary";
// bad = temp;
// }
// std::cout << bad << std::endl; // 정의되지 않은 동작!
return 0;
}
5. C++20 주요 기능¶
Concepts¶
#include <iostream>
#include <concepts>
#include <vector>
// concept 정의
template<typename T>
concept Numeric = std::is_arithmetic_v<T>;
template<typename T>
concept Printable = requires(T t) {
{ std::cout << t };
};
template<typename T>
concept Container = requires(T t) {
t.begin();
t.end();
t.size();
};
// concept 사용
template<Numeric T>
T add(T a, T b) {
return a + b;
}
// requires 절
template<typename T>
requires Printable<T>
void print(const T& value) {
std::cout << value << std::endl;
}
// 축약형
void printSize(Container auto& c) {
std::cout << "Size: " << c.size() << std::endl;
}
int main() {
std::cout << add(1, 2) << std::endl; // 3
std::cout << add(1.5, 2.5) << std::endl; // 4
// add("a", "b"); // 에러: Numeric 제약 불만족
print(42);
print("Hello");
std::vector<int> vec = {1, 2, 3};
printSize(vec); // Size: 3
return 0;
}
Ranges¶
#include <iostream>
#include <vector>
#include <ranges>
#include <algorithm>
int main() {
std::vector<int> numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
// 파이프라인 스타일
auto result = numbers
| std::views::filter([](int n) { return n % 2 == 0; }) // 짝수
| std::views::transform([](int n) { return n * n; }) // 제곱
| std::views::take(3); // 3개만
std::cout << "결과: ";
for (int n : result) {
std::cout << n << " "; // 4 16 36
}
std::cout << std::endl;
// 다양한 view
// iota: 숫자 범위 생성
for (int n : std::views::iota(1, 6)) {
std::cout << n << " "; // 1 2 3 4 5
}
std::cout << std::endl;
// reverse
for (int n : std::views::reverse(numbers)) {
std::cout << n << " "; // 10 9 8 7 6 5 4 3 2 1
}
std::cout << std::endl;
// drop: 처음 n개 건너뛰기
for (int n : numbers | std::views::drop(5)) {
std::cout << n << " "; // 6 7 8 9 10
}
std::cout << std::endl;
return 0;
}
삼중 비교 연산자 (Spaceship Operator)¶
#include <iostream>
#include <compare>
#include <string>
class Version {
public:
int major, minor, patch;
Version(int ma, int mi, int pa)
: major(ma), minor(mi), patch(pa) {}
// 삼중 비교 연산자 (C++20)
auto operator<=>(const Version& other) const = default;
// == 연산자도 자동 생성
};
int main() {
// 기본 타입
int a = 5, b = 10;
auto result = a <=> b;
if (result < 0) {
std::cout << "a < b" << std::endl;
} else if (result > 0) {
std::cout << "a > b" << std::endl;
} else {
std::cout << "a == b" << std::endl;
}
// 커스텀 클래스
Version v1{1, 2, 3};
Version v2{1, 3, 0};
if (v1 < v2) {
std::cout << "v1 < v2" << std::endl;
}
if (v1 == Version{1, 2, 3}) {
std::cout << "v1 == 1.2.3" << std::endl;
}
return 0;
}
모듈 (Modules)¶
// math.cppm (모듈 인터페이스)
export module math;
export int add(int a, int b) {
return a + b;
}
export int multiply(int a, int b) {
return a * b;
}
// main.cpp
import math;
import <iostream>;
int main() {
std::cout << add(3, 4) << std::endl; // 7
std::cout << multiply(3, 4) << std::endl; // 12
return 0;
}
// 컴파일 (컴파일러마다 다름)
// g++ -std=c++20 -fmodules-ts -c math.cppm
// g++ -std=c++20 -fmodules-ts main.cpp math.o -o main
코루틴 (Coroutines)¶
#include <iostream>
#include <coroutine>
// 간단한 Generator 예제
template<typename T>
struct Generator {
struct promise_type {
T value;
Generator get_return_object() {
return Generator{
std::coroutine_handle<promise_type>::from_promise(*this)
};
}
std::suspend_always initial_suspend() { return {}; }
std::suspend_always final_suspend() noexcept { return {}; }
std::suspend_always yield_value(T v) {
value = v;
return {};
}
void return_void() {}
void unhandled_exception() { std::terminate(); }
};
std::coroutine_handle<promise_type> handle;
Generator(std::coroutine_handle<promise_type> h) : handle(h) {}
~Generator() { if (handle) handle.destroy(); }
bool next() {
if (!handle.done()) {
handle.resume();
}
return !handle.done();
}
T value() { return handle.promise().value; }
};
Generator<int> range(int start, int end) {
for (int i = start; i < end; i++) {
co_yield i;
}
}
int main() {
auto gen = range(1, 5);
while (gen.next()) {
std::cout << gen.value() << " "; // 1 2 3 4
}
std::cout << std::endl;
return 0;
}
std::format (C++20)¶
#include <iostream>
#include <format>
#include <string>
int main() {
// 기본 사용
std::string s1 = std::format("Hello, {}!", "World");
std::cout << s1 << std::endl; // Hello, World!
// 인덱스 지정
std::string s2 = std::format("{1} + {0} = {2}", 10, 20, 30);
std::cout << s2 << std::endl; // 20 + 10 = 30
// 정렬과 너비
std::string s3 = std::format("|{:>10}|", 42); // 오른쪽 정렬
std::string s4 = std::format("|{:<10}|", 42); // 왼쪽 정렬
std::string s5 = std::format("|{:^10}|", 42); // 가운데 정렬
std::cout << s3 << std::endl; // | 42|
std::cout << s4 << std::endl; // |42 |
std::cout << s5 << std::endl; // | 42 |
// 숫자 형식
std::string s6 = std::format("{:b}", 42); // 이진수
std::string s7 = std::format("{:x}", 255); // 16진수
std::string s8 = std::format("{:.2f}", 3.14159); // 소수점 2자리
std::cout << s6 << std::endl; // 101010
std::cout << s7 << std::endl; // ff
std::cout << s8 << std::endl; // 3.14
return 0;
}
6. 모범 사례¶
코드 스타일 권장사항¶
#include <iostream>
#include <memory>
#include <vector>
#include <string>
// 1. auto를 적절히 사용
auto calculate() {
return 42; // 명확한 경우 auto 사용
}
// 2. const 적극 사용
void printVector(const std::vector<int>& vec) {
for (const auto& x : vec) {
std::cout << x << " ";
}
}
// 3. 스마트 포인터 사용
class Resource {
public:
void use() { std::cout << "사용" << std::endl; }
};
void goodMemoryManagement() {
auto ptr = std::make_unique<Resource>();
ptr->use();
// 자동 해제
}
// 4. 범위 기반 for 사용
void iterateModern(const std::vector<int>& vec) {
for (const auto& item : vec) {
std::cout << item << std::endl;
}
}
// 5. 초기화 리스트 사용
class Person {
private:
std::string name;
int age;
public:
Person(std::string n, int a)
: name(std::move(n)), age(a) {} // 이동 사용
};
// 6. noexcept 적절히 사용
void safeFunction() noexcept {
// 예외를 던지지 않는 함수
}
// 7. constexpr 활용
constexpr int maxSize = 100;
constexpr int square(int x) { return x * x; }
int main() {
std::vector<int> vec = {1, 2, 3, 4, 5};
printVector(vec);
std::cout << std::endl;
goodMemoryManagement();
iterateModern(vec);
constexpr int result = square(10);
std::cout << "10^2 = " << result << std::endl;
return 0;
}
7. 요약¶
| 버전 | 주요 기능 |
|---|---|
| C++11 | auto, 람다, 이동 시맨틱, 스마트 포인터, nullptr, constexpr |
| C++14 | 제네릭 람다, 변수 템플릿, 반환 타입 추론 |
| C++17 | 구조적 바인딩, if constexpr, optional, variant, filesystem |
| C++20 | Concepts, Ranges, 삼중 비교, 모듈, 코루틴, std::format |
8. 연습 문제¶
연습 1: 모던 C++ 리팩토링¶
기존 C++98/03 스타일 코드를 C++17 이상으로 리팩토링하세요.
연습 2: 타입 안전 설정 시스템¶
std::variant와 std::optional을 사용하여 타입 안전한 설정 관리 시스템을 구현하세요.
연습 3: 파이프라인 처리기¶
C++20 Ranges를 활용하여 데이터 처리 파이프라인을 구현하세요.
학습 완료¶
C++ 입문부터 모던 C++까지의 학습을 완료했습니다!
복습 추천 순서¶
- 기초 복습: 01~06 (변수, 함수, 포인터)
- OOP 복습: 07~09 (클래스, 상속)
- STL 복습: 10~11 (컨테이너, 알고리즘)
- 고급 복습: 12~15 (템플릿, 스마트 포인터, 모던 C++)
다음 학습 추천¶
- 디자인 패턴
- 멀티스레딩
- 네트워크 프로그래밍
- 실제 프로젝트 진행