C++ STL, 11

윤준혁·2025년 3월 3일

STL

STL이란?

  • 효율적인 데이터 구조 및 알고리즘을 제공하는 강력한 라이브러리
  • 데이터 구조, 반복자, 알고리즘을 쉽게 활용할 수 있다

알고리즘(Algorithms)

  • 정렬, 탐색, 변환 등의 알고리즘을 제공
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int main() {
    vector<int> vec = {5, 2, 8, 3, 1};
    sort(vec.begin(), vec.end()); // 정렬
    for (int v : vec) cout << v << " "; // 1 2 3 5 8
    return 0;
}

컨테이너(Container)

  • 데이터를 저장하는 구조이며, 크게 순차 컨테이너, 연관 컨테이너, 컨테이너 어댑터로 나뉜다
  • 다양한 데이터 구조(vector, list, map 등) 제공

반복자(Iterator)

  • 컨테이너의 요소를 순회하는 도구
#include <iostream>
#include <vector>
using namespace std;

int main() {
    vector<int> vec = {10, 20, 30};
    vector<int>::iterator it;
    for (it = vec.begin(); it != vec.end(); ++it) {
        cout << *it << " ";
    }
    return 0;
}

데이터 타입

스택(Stack)

  • LIFO(Last In First Out) 구조를 가지며, push(), pop(), toop() 메서드를 사용
#include <iostream>
#include <stack>
using namespace std;

int main() {
    stack<int> s;
    s.push(10);
    s.push(20);
    cout << s.top(); // 20
    s.pop();
    cout << s.top(); // 10
    return 0;
}

큐(Queue)

  • FIFO(First In First Out) 구조를 가지며, push(), pop(), front(), back() 메서드를 사용
#include <queue>
using namespace std;
queue<int> q;
q.push(1);
q.push(2);
cout << q.front(); // 1

디큐(Deque)

  • 양방향에서 삽입/삭제가 가능한 큐
#include <deque>
using namespace std;
deque<int> dq;
dq.push_front(10);
dq.push_back(20);

우선순위 큐(Priority Queue)

  • 최대 힙(기본값) 또는 최소 힙을 제공하는 컨테이너
#include <queue>
priority_queue<int> pq;
pq.push(3);
pq.push(5);
cout << pq.top(); // 5

맵(Map)

  • Key-Value 형태의 데이터를 저장하는 연관 컨테이너
#include <map>
map<string, int> myMap;
myMap["Alice"] = 30;
cout << myMap["Alice"]; // 30

셋(Set)

  • 중복을 허용하지 않는 데이터 구조
#include <set>
set<int> mySet;
mySet.insert(10);
mySet.insert(20);

벡터(Vector)

  • 동적 배열을 제공하며, push_back(), size() 등을 사용할 수 있다
#include <vector>
vector<int> v = {1, 2, 3};
v.push_back(4);

리스트(List)

  • 이중 연결 리스트를 구현한 컨테이너
#include <list>
list<int> myList;
myList.push_back(10);

C++11

C++11이란?

  • C++의 기능을 대폭 개선한 주요 업데이트로, 타입 추론, 람다 표현식, 스마트 포인터, 가변 인자 등의 다양한 기능이 추가되었다

Auto

  • 컴파일러가 변수의 타입을 자동으로 추론하도록 한다
  • 타입을 명시하지 않고도 직관적인 코드를 작성할 수 있다
  • 코드의 가독성이 향상되고, 유지보수가 쉬워지며, 긴 타입 이름을 자동으로 처리
#include <iostream>
#include <vector>
using namespace std;

int main() {
    auto x = 10;      // int
    auto pi = 3.14;   // double
    auto name = "Alice"; // const char*
    
    vector<int> vec = {1, 2, 3};
    auto it = vec.begin(); // vector<int>::iterator
    
    cout << *it << endl; // 1
    return 0;
}

사용 목적

  • 반복자와 같은 긴 타입을 간결하게 표현
  • 특정 타입을 변경할 경우, 모든 변수 타입을 일일이 수정하지 않아도 된다
  • 템플릿과 함께 사용하여 유연한 코드를 작성할 수 있다

decltype

  • 변수나 표현식의 타입을 결정하는 데 사용
  • auto와 달리 변수를 초기화하지 않고 타입을 추론할 수 있다
#include <iostream>
using namespace std;

int main() {
    int x = 42;
    decltype(x) y = 10; // y는 int 타입
    cout << y << endl;
    return 0;
}

사용 목적

  • 표현식의 타입을 그대로 유지할 때 사용
  • auto보다 더 정밀하게 타입을 결정할 때 사용

decltype(auto)

  • 반환값의 타입을 유추할 수 있다
auto getValue() -> decltype(42) {
    return 42;
}

Final

  • 클래스 및 가상 함수에서 final 키워드를 사용하여 상속 또는 오버라이딩을 금지할 수 있다
class Base {
public:
    virtual void show() final { // 더 이상 오버라이딩 불가능
        cout << "Base class" << endl;
    }
};

class Derived : public Base {
    // void show() override;  // 오류! 'show'는 final로 선언됨
};

class FinalClass final {}; // 상속 불가
class DerivedClass : public FinalClass {}; // 오류 발생

사용 목적

  • 특정 클래스의 상속을 방지하고 싶을 때 사용
  • 특정 멤버 함수의 재정의를 막고 싶을 때 사용

Lambda

  • 익명 함수를 간결하게 정의하는 기능
#include <iostream>
using namespace std;

int main() {
    auto add = [](int a, int b) { return a + b; };
    cout << add(10, 20) << endl; // 30
    return 0;
}
int x = 10;
auto lambda = [x]() { return x * 2; };
cout << lambda(); // 20

사용 목적

  • 간단한 콜백 함수를 정의할 때
  • STL 알고리즘에서 사용자 정의 함수로 활용할 때
  • 함수 객체(functor) 대신 사용하여 가독성 향상

스마트 포인터(Smart Pointers)

  • 메모리 누수를 방지하기 위해 unique_ptr, shared_ptr, weak_ptr이 도입되었다

unique_ptr

  • 단독 소유 스마트 포인터
  • 하나의 포인터만 특정 객체를 소유할 수 있는 스마트 포인터
  • 다른 unique_ptr에 할당할 수 없으며, move()를 사용하여 소유권을 이동할 수 있다
#include <memory>
unique_ptr<int> ptr = make_unique<int>(10);
cout << *ptr << endl; // 10

shared_ptr

  • 공동 소유 스마트 포인터
  • 여러 개의 포인터가 같은 객체를 공유할 수 있는 스마트 포인터
  • 참조 카운트를 유지하며, 마지막 shared_ptr이 소멸될 때 메모리를 해제한다
#include <memory>
shared_ptr<int> p1 = make_shared<int>(20);
shared_ptr<int> p2 = p1;
cout << *p2 << endl; // 20

weak_ptr

  • 순환 참조 방지 스마트 포인터
  • shared_ptr과 함께 사용되며, 참조 카운트 증가 없이 객체를 참조할 수 있다
  • shared_ptr간의 순환 참조 문제를 방지하는데 사용된다
#include <memory>
weak_ptr<int> wptr;

In-Class Initializer & Delegation of Contructors

클래스 내 초기화(In-Class Initializer)

class MyClass {
public:
    int x = 10;
};

생성자 위임(Delegation of Contructors)

class MyClass {
public:
    int x;
    MyClass(int a) : x(a) {}
    MyClass() : MyClass(0) {} // 생성자 위임
};

가변 인자(Ellipsis)

  • 임의 개수의 인자를 받을 수 있는 기능
#include <iostream>
using namespace std;

template<typename... Args>
void print(Args... args) {
    (cout << ... << args) << endl;
}

int main() {
    print(1, 2, 3, "Hello");
    return 0;
}

0개의 댓글