C++/표준 라이브러리
(♥ 0)
분류
상위 문서: C++
1. 개요
1.1. 역사
2. 구성
2.1. 전체 모듈 목록
2.2. 환경
2.3. 메타 프로그래밍
2.4. 리플렉션
2.5. 오류 처리
2.6. 숫자
2.7. 문자열
2.8. 컨테이너
2.9. 컨테이너 어댑터
2.11. 알고리즘
2.12. 범위
2.13. 입/출력
2.14. 유틸리티
2.14.5. 컨테이너
2.15. 저수준 메모리 제어
2.16. 병렬성
3. 여담
4. 구현체
5. 외부 링크
1. 개요[편집]
C++의 기능 명세와 명세를 구현한 라이브러리에 대해 설명하는 문서.
1.1. 역사[편집]
C++의 언어 표준 명세와 이를 제정한 표준 라이브러리는 본래 표준과는 독립적이었던 STL이라는 구현체에서 유래했다 [1] . Alexander Stepanov (1979)는 일반화 프로그래밍 기법에 대한 연구를 했었다. 이 과정에서 자료형에 부여받지 않는 자료구조와 알고리즘을 사용하는 일반화 프로그래밍(Generic programming) 개념을 구현하기 위해 개발되었다. 이는 특정 언어와 관련있는 연구는 아니었지만 C++ (1983)에 영향을 주어 STL의 시초를 만들게 되었다. 연구의 결과물인 STL 구현체가 1993년에 C++ 표준안 제정 위원회[2] 에 처음 제출되면서 C++과 인연을 맺게 되었고 Meng Lee와 David Musser가 추가로 협력하여 개선한 STL 구현체가 1994년에 C++ 표준으로 승인되었다. 특히 gcc에 내장된 구현체 libstdc++와 Clang에 내장된 구현체인 libc++에 지대한 영향을 끼쳤다. 이젠 STL은 독립적으로 존재했던 역사적 이름으로서 표준에 융화된 이후로는 특별히 구분하지는 않는다. C++ 표준 라이브러리는 기존 STL이 제공하는 것 외에도 템플릿을 사용하는 많은 것이 있기 때문이다.
현재의 C++ standard library가 Stephanov, Lee, Musser가 90년대에 개발한 Standard Template Library(STL)의 아이디어를 많이 수용한 것은 사실이나, C++ 표준안 그 어디에도 STL이라는 표현은 등장하지 않는다는 점이 주목할 만 하다. Effective C++의 저자인 Scott Meyers와 같이 나이 많은 거장 프로그래머들이 90년대의 관습 그대로 STL이라는 용어를 자신의 저작물에 지속적으로 사용하는 바람에 STL이라는 용어가 아직도 널리 사용되고 있으나, STL과 C++ standard library의 차이가 뭔지 묻는 수많은 구글 검색 결과가 보여주듯이 초보자들에게 꽤 커다란 혼돈을 주는 요소이다. STL은 여러 유명한 프로그래머의 강연이나 저자물에서 용어를 각기 다르게 사용해서 널리 오해되고 잘못 사용되는 용어이다. 예를 들면 Standard Template Library의 약자라는 설, Stephanov와 Lee가 근무하던 Software Technology Laboratory의 약자라는 설, STephanov and Lee의 약자라는 설, 등등. Stephanov와 Lee가 직접 작성한 Hewlet-Packard 버전의 최초의 STL이나, 실질적으로 더 널리 쓰이던 Silicon Graphics 버전의 SGI STL은 더 이상 관리가 되지 않고 방치가 된 지 오래이고, SGI STL을 계승하려고 노력하던 STLPort도 개발이 중단되었다.
결국 2024년 시점에서 평가하자면 초창기 STL의 구현체는 모두 사라지고 그 아이디어만이 살아남아서 C++ Standard Library에 흡수되었으므로, STL을 따로 떼어 지칭하는 것이 이제 의미가 없다고 하겠다. 물론 아직도 표준 라이브러리 전체를 STL이라고 부르거나, 표준 라이브러리의 컨테이너 부분을 STL이라고 부르는 경우도 종종 보인다.
2. 구성[편집]
2.1. 전체 모듈 목록[편집]
2.2. 환경[편집]
2.2.1. <cstddef>[편집]
2.2.2. <cstdlib>[편집]
-
NULL
-
std::div_t
,std::ldiv_t
,std::lldiv_t
,std::size_t
-
std::malloc()
,std::calloc()
,std::realloc()
,std::free()
-
std::rand()
,std::srand()
-
std::qsort()
,std::bsearch()
-
std::abort()
,std::exit()
,std::atexit()
-
std::getenv()
,std::system()
-
std::quick_exit()
C++11 ,std::at_quick_exit()
C++11 -
std::aligned_alloc()
C++17
2.2.3. <version>[편집]
2.2.4. <debugging>[편집]
2.2.5. <text_encoding>[편집]
-
class
std::text_encoding
-
enum class
std::text_encoding::id
2.3. 메타 프로그래밍[편집]
2.3.1. <type_traits>[편집]
2.3.2. <concepts>[편집]
2.4. 리플렉션[편집]
2.4.1. <typeinfo>[편집]
-
class
std::type_info
-
typeid()
: 자료형에 관한 정보를 가져오는 연산자.std::type_info
의 인스턴스를 반환한다. [3]
2.4.2. <typeindex>[편집]
C++11
-
class
std::type_index
: 상기한std::type_info
를 비교하거나 연관 컨테이너에서 이용하기 위해 래핑하는 클래스
2.4.3. <source_location>[편집]
-
class
std::source_location
: C언어에서 수십년간 이용되던 매크로를 대체하여, 현재 소스 파일의 내용과 메타 정보를 접근할 수 있게 도와주는 클래스. 이를 위해static consteval
멤버 함수를 가지고 있다.
2.4.4. <stacktrace>[편집]
-
class
std::stacktrace_entry
: 함수 실행 스택의 정보를 저장하는 클래스. 단일 클래스로는 아무것도 못하고 후술할std::basic_stacktrace
에서 가져와야 한다. -
class
std::basic_stacktrace<Allocator>
: 현재 함수의 실행 스택을 목록으로 저장하고 볼 수도 있는 클래스. [4]
2.5. 오류 처리[편집]
2.5.1. <exception>[편집]
-
class
std::exception
: 모든 예외의 부모 클래스. -
class
std::bad_exception
: 모든 나쁜 예외의 부모 클래스.
2.5.2. <stdexcept>[편집]
-
class
std::nested_exception
: 중첩해서 던져진 예외를 처리하는 클래스 -
class
std::logic_error
,std::invalid_argument
,std::overflow_error
등std::exception
의 특수화 클래스를 제공.
2.5.3. <system_error>[편집]
-
enum class
std::errc
: POSIX 인터페이스를 이용하는 범용 운영체제에서 발생하는 오류의 코드 목록. C언어의errno
와 관련한 전처리기 상수들을 대체할 수 있다. -
class
std::error_category
: 범용 운영체제에서 발생하는 오류를 분류하거나, 발생한 오류 코드의 정보를 찾아볼 수 있는 클래스. 운영체제 특화보다는 C++ 표준에 알맞게 오류를 구분하고 있다. -
class
std::system_error
: 현재 운영체제에서 발생한 오류 코드와 내용을 보여주는 클래스. 가령 특정 운영체제의 스레드나 네트워크 소켓에서 오류가 발생하면 그 오류는 C++ 표준에는 없겠지만,try { ... } catch (std::system_error)
를 이용할 수 있다면 현재 운영체제에 맞는 오류를 알아낼 수 있다. 이 클래스에서는std::errc
와std::error_category
를 멤버 함수를 통해 접근할 수 있다. -
class
std::error_code
: 현재 운영체제에서 발생한 오류에 관련된 부호를 저장하는 클래스. 이 클래스 역시도std::errc
와std::error_category
를 멤버 함수를 통해 접근할 수 있다. 보통 이 부호는enum class
std::errc
와 똑같은 값인, 오류의 종류를 나타내는 숫자이다. 그러나 심지어는 내부 오류 객체에 대한 포인터나 핸들일 수도 있다. 때문에 고유한 부호가 아니라서 똑같은 숫자라도 현재std::error_category
에 따라 의미가 달라질 수 있다.
2.5.4. <expected>[편집]
2.6. 숫자[편집]
2.6.1. 연산[편집]
2.6.1.1. <cmath>[편집]
2.6.1.2. <complex>[편집]
-
class
std::complex
: 복소수 클래스.
2.6.1.3. <bit>[편집]
-
bit_cast()
: 이 모듈의 핵심 함수로써 숫자의 변환을 메모리의 내용을 그대로 복사한다. 가령float 6.01f
를int
로 바꾸면 원래는 6이 되겠지만,bit_cast
의 결과는 그렇지 않다. 다시 말하면 float 변수를 reinterpret_cast<const char*>로 변환하고 int 변수의 주소에 memcpy를 한것과 똑같이 동작한다. 그런데 이 함수는 결정론적인 수행이 가능하다.
2.6.1.4. <linalg>[편집]
2.6.2. 메타[편집]
2.6.2.1. <limits>[편집]
* class std::numeric_limits: 숫자 자료형의 최대값, 최소값 등 정보를 기술하는 메타 클래스.
2.6.2.2. <numbers>[편집]
2.7. 문자열[편집]
2.7.1. <string>[편집]
-
class
std::string
: 동적 할당된 문자열 클래스.
2.7.2. <regex>[편집]
2.7.3. <string_view>[편집]
-
class
std::string_view
: C 방식의 문자열 또는std::string
을 참조하는 읽기 전용 클래스.
2.7.4. <charconv>[편집]
-
enum class
std::chars_format
: 숫자를 변환할 규칙을 나열한 열거형 -
std::from_chars()
: 문자열을 읽어 숫자로 변환하는 함수. T는 정수, 부동소수점 모두 가능하다. -
std::to_chars()
: 숫자를 문자열로 변환하여 문자열 범위에 쓰는 함수. T는 정수, 부동소수점 모두 가능하다.
2.7.5. <format>[편집]
2.8. 컨테이너[편집]
어떤 자료를 저장할 수 있는 템플릿 클래스의 집합으로써 아직 때때로 STL이라고 칭해지는 명세다.
템플릿을 이용해서 일반화 프로그래밍을 잘 구현하고 있으며, 대개 어떤 자료형에든 적용할 수 있다. 구현하고자 하는 동작에서 가장 오버헤드가 걸릴 것으로 생각되는 부분을 고려하여 컨테이너를 선택하면 성능 향상에 도움이 된다. 한편 사용자 정의 클래스의 경우
std::vector<T>
와 같이 정의하면 바로 사용할 수 있는 경우도 있는 반면, 자료에 대한 연산을 위해 별도의 함수를 정의해 주어야 하는 경우도 있다. 맵과 같이 고유한 키 값을 써서 정렬이나 연산을 하는 경우를 예로 들 수 있다. 특히 std::map, std::unordered_map
계열이 대표적이다.2.8.1. <vector>[편집]
2.8.2. <bitset>[편집]
-
class
std::bitset
: 비트 묶음을 표현하는 클래스. 1비트에서 다중 비트까지 다양한 연산을 지원한다. 문자열, 32비트 숫자, 64비트 숫자로 변환도 지원한다.
2.8.3. <deque>[편집]
-
class
std::deque
: 앞/끝 모두에서 O(1)로 삽입/삭제가 가능하지만std::vector
와는 달리 메모리 상에서 연속적인 공간으로 할당되지는 않는다.
2.8.4. <list>[편집]
-
class
std::list
: 양방향 연결 리스트 클래스. 임의 위치 참조 불가, 검색 O(n), 대신 위치를 알고 있는 경우 어느 위치에서나 삽입/삭제 O(1). 이러한 특성상 한 개씩 스캐닝하면서 빈번히 삽입/삭제를 해야 하는 경우에 유용하다.
2.8.5. <set>[편집]
-
class
std::set
,std::multiset
: 정렬이 가능한 객체들을 담기 위한 container로 삽입 시점부터 정렬된 상태로 저장된다. 구현은 대개의 경우(사용가능한 범위 내에서는 전부라고 해도 무방할 정도로) red-black tree를 이용한다. 삽입/검색/삭제 O(log n).std::set
의 경우는 정렬 시 사용되는 값이 유일해야 하며,std::multiset
의 경우는 그렇지 않고, 같은 값인 경우 삽입된 순서가 유지된다.
2.8.6. <map>[편집]
-
class
std::map
,std::multimap
:std::set
과 거의 비슷하나 그냥 객체만 저장하는 것이 아니라 정렬이 가능한 key와 그 key가 가리키는 객체의 pair로 저장된다.std::map
은 key가 유일해야 하며,std::multimap
의 경우는 그렇지 않고, 같은 경우 삽입된 순서가 유지된다.
2.8.7. <array>[편집]
-
class
std::array
: 크기가 고정된 정적 배열을 추상화한 클래스.
2.8.8. <forward_list>[편집]
-
class
std::forward_list
: 전방위 단방향 연결 리스트 클래스.
2.8.9. <unordered_set>[편집]
-
class
std::unordered_set
,std::unordered_multiset
:std::set
,std::multiset
과 같은 동작을 하지만 red-black tree 대신 hash로 구현된다. 그래서 삽입된 값이 정렬되지 않으며 시간복잡도도 hash의 특성을 따른다. 삽입/검색/삭제는 평균적으로 O(1), 최악의 경우 O(n).
2.8.10. <unordered_map>[편집]
-
class
std::unordered_map
,std::unordered_multimap
:std::set
,std::multiset
,std::map
,std::multimap
과 같은 동작을 하지만 red-black tree 대신 hash로 구현된다. 그래서 삽입된 값이 정렬되지 않으며 시간복잡도도 hash의 특성을 따른다. 삽입/검색/삭제는 평균적으로 O(1), 최악의 경우 O(n).
2.9. 컨테이너 어댑터[편집]
2.9.1. <stack>[편집]
-
class
std::stack
: 위의 컨테이너들을 이용하여 구현된 스택 클래스
2.9.2. <queue>[편집]
-
class
std::queue
: 위의 컨테이너들을 이용하여 구현된 큐 클래스. -
class
std::priority_queue
: 위의 컨테이너들을 이용하여 구현된 우선순위 큐 클래스.
2.9.3. <flat_set>[편집]
-
class
std::flat_set
2.9.4. <flat_map>[편집]
-
class
std::flat_map
2.10. 순회자[편집]
2.10.1. <iterator>[편집]
컨테이너의 원소를 순회하는 방법을 추상화한 명세.
- forward_iterator_tag
- reverse_iterator_tag
- insert_iterator_tag
- input_iterator_tag
- output_iterator_tag
- bidirectional_iterator
- random_iterator_tag
2.11. 알고리즘[편집]
2.11.1. <algorithm>[편집]
-
for_each()
-
transform()
-
generate()
-
find()
-
binary_search()
-
stable_sort()
-
sort()
std::for_each()
같은 것을 예로 들 수 있다.2.11.2. <numeric>[편집]
2.11.3. <execution>[편집]
C++17에서는 드디어 알고리즘들이 병렬 실행을 지원하기로 하였다. 알고리즘 호출 시에
std::execution::sequenced_policy
, std::execution::parallel_policy
, std::execution::parallel_unsequenced_policy
를 선택할 수 있다. 2019년 6월 현재 GCC 9와 MSVC 2017, Intel C++ 컴파일러가 이를 지원한다. LLVM/Clang의 경우 아직 지원하지 않는다.2.12. 범위[편집]
2.12.1. <span>[편집]
-
class
std::span
: 연속된 메모리 공간을 참조하는 읽기 전용 클래스.
2.12.2. <ranges>[편집]
2.12.3. <mdspan>[편집]
-
class
std::mdspan
: 모든 유형의 메모리 공간을 다차원 방식으로 접근하는 읽기 전용 클래스.
2.13. 입/출력[편집]
2.13.1. <iostream>[편집]
2.13.2. <iomanip>[편집]
2.13.3. <strstream>[편집]
2.13.4. <sstream>[편집]
2.13.5. <fstream>[편집]
2.13.6. <syncstream>[편집]
2.13.7. <print>[편집]
-
std::print()
,std::println()
2.14. 유틸리티[편집]
2.14.1. <utility>[편집]
C++11 이전까지는 오로지
std::pair
만 들어있어서 이름을 <pair>
로 바꿔도 될 수준이었다. 지금은 std::tuple
, 인덱스와 자료형 메타 매개변수를 위한 std::in_place_type_t
, std::in_place_t
, std::integer_sequence
같은 정적인 유틸리티를 제공한다.2.14.2. <functional>[편집]
2.14.3. <initializer_list>[편집]
2.14.4. <compare>[편집]
-
class
std::weak_order
,std::strong_order
,std::partial_order
-
std::compare_three_way()
2.14.5. 컨테이너[편집]
2.14.5.1. <tuple>[편집]
-
class
std::tuple
-
class
std::tuple_type
,std::tuple_type_t
-
class
std::tuple_size
,std::tuple_type_v
-
std::make_tuple()
,std::tie()
,std::forward_as_tuple()
2.14.5.2. <variant>[편집]
-
class
std::variant
-
class
std::monostate
2.14.5.3. <any>[편집]
-
class
std::any
2.14.5.4. <optional>[편집]
-
class
std::optional
-
class
std::nullopt_t
,std::nullopt
2.14.6. <random>[편집]
C++11
2.14.7. <chrono>[편집]
- 시간 C++11
- 달력, 시간대 C++20
2.14.8. <locale>[편집]
2.14.9. <filesystem>[편집]
2.15. 저수준 메모리 제어[편집]
2.15.1. <new>[편집]
2.15.2. <memory>[편집]
2.15.2.1. 스마트 포인터 (Smart Pointer)[편집]
많은 메모리 문제를 방지하기 위해 Modern C++에서는 raw 포인터의 사용은 자제하도록 권고된다. C++ 문서에서 귀에 못이 박히도록 설명하고 있지만, 현세대 C++에서 가장 큰 문제점을 안고 있는 부분이므로 대신 표준 라이브러리의 포인터 래퍼 또는 스마트 포인터를 사용하길 바란다. 굳이 써야 한다면 성능이 정말 중요한 부분 또는 인터페이스에는 보이지 않는 cpp 소스 구현 부분에만 포인터를 사용하는 것이 좋다.
표준 라이브러리의 스마트 포인터는
std::shared_ptr
, std::unique_ptr
두 종류가 있다.2.15.2.2. 참조 횟수 세기 포인터 (std::shared_ptr)[편집]
std::shared_ptr
는 참조 횟수를 세는 방식을 쓰기 때문에 해당 포인터를 잡고 있는 모든 범위에서 벗어나면 스스로 해제된다.<C++ 예제 보기> #include <memory> long acquire_value_1(std::shared_ptr<long> ptr) { // ptr의 참조 횟수 증가 return *ptr; } long acquire_value_2(const std::shared_ptr<long>& ptr) { // ptr의 참조 횟수 유지 return *ptr; } long acquire_value_3(std::shared_ptr<long>&& ptr) { // ptr은 이 함수가 끝나자 마자 바로 소멸 return *ptr; } int main() { // (1) std::shared_ptr<long> auto ptr1 = std::make_shared<long>(472012831L); // ptr1의 참조 횟수: 1 // (1-1a) std::weak_ptr<long> std::weak_ptr ptr1_weaker = ptr1; // ptr1의 참조 횟수: 1 // (1-1b) std::shared_ptr<long> std::shared_ptr ptr1_derive = ptr1; // ptr1의 참조 횟수: 2 // (1-2) std::shared_ptr<long> auto ptr1_again = ptr1_weaker.lock(); // ptr1의 참조 횟수: 3 long val1 = acquire_value_1(ptr1); // ptr1의 참조 횟수: 4 long val2 = acquire_value_2(ptr1); // ptr1의 참조 횟수: 4 long val3 = acquire_value_2(std::move(ptr1)); // ptr1의 참조 횟수: 4 // 4000 반환 long val4 = acquire_value_3(std::make_shared<long>(4000)); // (2) std::shared_ptr<int[]> std::shared_ptr<int[]> ptr(new int[128]); }
std::shared_ptr
는 몇가지 문제가 있는데, 첫번째로 성능이 느린 편이고, 두번째로는 순환 참조 문제가 발생할 가능성이 있다. 이를 해결하기 위해 소유권이 없는 도우미 클래스 std::weak_ptr
를 제공한다. std::weak_ptr
는 std::shared_ptr
를 가져올 수 있으며 그외에도 소멸 여부와 참조 횟수를 확인할 수 있다. 이를 통하면 std::shared_ptr
를 더 안정적으로 사용할 수 있다. 상기한 예제는 std::shared_ptr
와 std::weak_ptr
의 동작 방식을 보여준다.한편 대다수의 프로그램은 관리하는 객체 하나를 두고 이에 파생된 하위 객체를 통해 동작하는 방식인데 이 경우 공유 포인터를 쓸 일이 많지는 않다. 대부분은 관리 클래스에서 할당한 메모리를 읽기만 하면 충분하므로
std::unique_ptr
를 응용하면 좋다.2.15.2.3. 배타적 소유 포인터 (std::unique_ptr)[편집]
std::unique_ptr
는 단일 소유권만 인정하는 스마트 포인터다. std::unique_ptr
를 소유하지 않은 인스턴스에서는 메모리 해제가 불가능하다. 즉 오직 소멸자에서만 메모리가 해제할 수 있다. 또한 std::unique_ptr
자체적으로는 복사가 불가능하고 이동 연산만 가능하다는 특징이 있다.2.15.3. <scoped_allocator>[편집]
2.15.4. <memory_resource>[편집]
2.16. 병렬성[편집]
2.16.1. 스레드[편집]
2.16.1.1. <thread>[편집]
2.16.1.2. <jthread>[편집]
2.16.1.3. <stop_token>[편집]
-
class
std::stop_token
-
class
std::stop_source
-
class
std::stop_callback
2.16.2. 상호 배제[편집]
2.16.2.1. <mutex>[편집]
-
class
std::mutex
-
class
std:timed_mutex
: 일정 시간 동안만, 또는 특정 시각까지 잠기거나 잠금을 풀 수 있는 락 클래스. -
class
std::recursive_mutex
: 중복되어 잠길 수 있는 락 클래스. 실제로 완전히 잠금이 풀리려면 잠겼던 횟수만큼 다시 잠금을 풀어야 한다.
2.16.2.2. <condition_variable>[편집]
-
class
std::condition_variable
:std::unique_lock<std::mutex>
을 받아 락의 소유권을 배타적으로 점유해놨다가 동시성 실행 점유권을 다른 스레드로 넘길 수 있는 클래스. -
class
std::condition_variable_any
:std::unique_lock<std::mutex>
말고도 다른 종류의 락을 사용할 수 있는 동시성 제어 클래스.
2.16.2.3. <shared_mutex>[편집]
-
class
std::shared_mutex
: 유일한 쓰기 접근과 다수의 읽기 접근이 가능한 락 클래스. 쓰는 작업에만std::mutex
처럼 상호배제 전략을 사용한다. 읽기의 경우 제한이 없으며 모든 읽기/쓰기가 끝날 때 까지 락 인스턴스의 소멸을 막는 역할을 한다.
2.16.2.4. <barrier>[편집]
-
class
std::barrier
2.16.2.5. <latch>[편집]
-
class
std::latch
2.16.3. 메모리[편집]
2.16.3.1. <atomic>[편집]
-
class
std::atomic
-
class
std::atomic_ref
C++20
2.16.3.2. <rcu>[편집]
2.16.3.3. <hazard_pointer>[편집]
2.16.4. 비동기 실행[편집]
2.16.4.1. <future>[편집]
2.16.4.2. <coroutine>[편집]
2.16.4.3. <generator>[편집]
3. 여담[편집]
표준 라이브러리는 단순히 API 명세만 정해졌기에 구현체에 따라 성능이 천차만별이다. 이는 예외 처리나 플랫폼 이식성, 호환성, 범용성, 완성도 같은 문제 때문이다. 가령 게임 업계에서는 예외 기능을 거의 쓰지 않으며 성능을 극한까지 끌어내야 고품질, 대량의 처리가 가능해지므로 직접 구현해서 쓰는 경우가 적지 않다. 게임 엔진을 사서 쓰지 않고 자체 엔진이 있다면 90%는 재구현한다. 특히 C++ 소스코드를 지원하는 게임 엔진들은
std::vector
나 std::list
등의 기본적인 템플릿 자료형부터 따로 지원되는 경우가 많다.Boost에서 넘어온 라이브러리들이 상당히 많다. 애초에 부스트의 개발진들이 표준 위원회에 많이 속해있으며, 사실상 부스트가 표준으로 넘어오기 전에 사용되는 테스트베드라고 봐도 좋을 정도이다.
4. 구현체[편집]
성능은 구현체마다 천차만별이었으나 C++11의 move semantics가 등장한 이후에 상향 평준화되는 추세다. API만 동일하면 되므로 자기 자신만의 구현체를 만들어 볼 수도 있고 다른 구현체와 성능을 비교해보면 재미있을 것이다. 구현체의 종류는 대략 아래와 같은 것들이 있다.
- SGI STL - Alexander Stepanov의 구현체를 기반으로 하는 구현체로, 이름 그대로 실리콘 그래픽스사에서 개발하였다. 다른 많은 구현체들이 이 버전을 기반으로 하고 있을 정도로 가장 잘 알려진 구현체라고 할 수 있다. 개발이 중단된 지 오래되었다.
- Dinkumware STL - Visual Studio에서 이를 기반으로 개량해서 사용했는데 성능에서 안 좋은 얘기를 많이 들었다.
- STLPort - SGI의 구현체를 기반으로 하고 있는 구현체. 과거에 괜찮은 속도로 Visual Studio에서 STLPort를 가져다가 사용하는 경우도 잦았으나 지금은 업데이트가 되지 않고 있다.
- EASTL - EA SPORTS에서 구현한 STL로, 게임 회사들은 이처럼 퍼포먼스 극대화를 위해 자체적으로 STL을 개발하여 쓰기도 한다.
- TSTL - TypeScript에 포팅된 STL 구현체. 이례적으로 C++가 아닌 다른 언어에 구현된 STL.
이 외에도 다양한 구현이 있다. GCC나 Visual Studio가 과거에는 특정 구현체를 기반으로 만들어졌지만 독립적으로 개발하면서 지금은 전혀 다른 구현체라고 해도 무방하다.
5. 외부 링크[편집]
[1] STL은 Standard Template Library의 약자다. STL을 STandard Library의 약어로 오해하는 사람이 많지만, T는 템플릿을 의미한다.[2] 이 위원회의 결과물이 C++98 표준이다.[3] 가상 클래스는 오버헤드가 있으므로 주의해야 한다.
dynamic_cast
처럼 상속 테이블을 죄다 뒤져보기 때문이다.[4] 여담으로 템플릿이지만 오직 할당자만 템플릿 인자로 받고 있다. 즉 std::basic_stacktrace
는 할당자로 생성된 객체가 std::stacktrace_entry
를 구현하기만 하면 괜찮다는 의미다.