readme.md
기록소
readme.md
전체 방문자
오늘
어제
  • 분류 전체보기
    • 네트워크
      • HTTP
      • 윈도우 소켓 프로그래밍
    • Windows API
    • 그래픽스
      • DirectX11
    • 일반
      • Linux
      • 데이터베이스
      • 팁
      • 책 후기
    • 쿠버네티스
    • 프로그래밍 언어
      • C#
      • Java
      • Go
      • C++
      • Lua
    • 책
      • 이펙티브 C++
      • 제프리 리처의 WINDOWS VIA C, C++
    • 기타

블로그 메뉴

  • 홈
  • 태그

공지사항

인기 글

태그

  • 소멸자
  • new
  • 소켓 프로그래밍
  • emplace
  • id3d11shaderresourceview
  • 가상함수
  • imagestride
  • 윈도우 소켓
  • 상속
  • const
  • 인터페이스
  • Delete
  • DirectX
  • 템플릿
  • 생성자
  • directx11
  • C++
  • windowsAPI
  • phong
  • 자원관리
  • 캐스팅
  • 설계
  • CPP
  • 자바8
  • consteval
  • 초기화
  • 대입연산자
  • 버텍스 버퍼
  • wm_keyup
  • Graphics

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
readme.md

기록소

책/이펙티브 C++

이펙티브 C++(381p ~ 392p)

2024. 2. 15. 21:08

이펙티브 C++
https://www.yes24.com/Product/Goods/17525589
페이지 381p ~ 392p

이펙티브 C++(381p ~ 392p)

요약

항목 54: TR1을 포함한 표준 라이브러리 구성요소와 편안한 친구가 되자

  • C++은 언어 자체의 기능 외의 새로운 기능들 대부분은 기존의 표준 라이브버리에 추가되는 형태로 버전업이 되고 있다.
  • TR1(1차 기술 보고서, Technical Report 1)이 이에 포함된다.
  • TR1이 포함된 것을 가리켜 C++ 표준 1.1이라고 부르는 경우를 볼 수 있는 것도 이런 의미 때문이며, TR1의 기능은 사실상 모든 종류의 라이브러리와 응용프로그램에 영향을 미치고 있다.
  • TR1에 무엇이 들어 있는지 살펴보는 역사적인 순간에, C++98에 명시되어 있는 표준 C++ 라이브러리의 주요 구성요소를 되짚어 보는 것도 좋을 것이다.

표준 템플릿 라이브러리(Standard Template Library: STL)

  • 주요 구성요소로서 컨테이너(vector, string, map 등), 반복자, 알고리즘(find, sort, transform 등), 함수 객체(less, greater) 외에 이런저런 컨테이너 어댑터와 함수 객체 어댑터(stack, priority_queue, mem_fun, not1 등)가 있다.

iostream

  • 사용자 정의 버퍼링, 국제화 기능이 가능한 입출력을 지원하며, 그 외에 cin, cout, cerr, clog 등의 사전정의 객체를 지원한다.

국제화 지원

  • 여러 로케일(locale)을 활성화시킬 수 있는 기능이 포함되어 있다. 또한 wchar_t 등의 타입(대개 16비트/문자) 및 wstring(wchar_t 타입으로 정의한 string)을 쓰면 유니코드를 사용할 수 있다.

수치 처리 지원

  • 복소수를 나타내는 템플릿(complex) 및 수치 배열을 나타내는 템플릿(valarray)이 여기에 해당된다.

예외 클래스 계통

  • 최상위 클래스인 exception 및 이것으로부터 갈라져 나온 파생 클래스들, 예를 들어 logic_error 및 runtime_error 등이 여기에 포함된다.

C89의 표준 라이브러리

  • 1989년 버전의 C에 포함된 표준 라이브러리는 전부 C++에도 들어 있다.

  • TR1을 통해 명시된 새로운 구성요소는 총 14개이다.

  • 14개 모두 std 네임스페이스에 들어 있는데, 더 정확히 말하면 std 안에 중첩된 tr1이란 네임스페이스에 있다.

  • 이 책에서 예제 코드에 등장한 TR1의 구성요소부터 정리하면 다음과 같다.

스마트 포인터

  • tr1::shared_ptr, tr1::weak_ptr이 여기에 해당한다. 동작은 기본제공 포인터와 똑같으나, 하나의 실체 객체를 가리키는 자신과 같은 포인터의 개수를 유지해 놓는 똑똑한 포인터이다.
  • 이런 기법을 가리켜 참조 카운팅이라고 부른다.
  • 어떤 객체를 가리키는 최후의 스마트 포인터가 소멸될 때(참조 카운트가 0이 될 때), 그 객체도 자동으로 삭제한다.
  • 스마트 포인터는 비순환형 자료구조 내의 자원 누출을 방지하는 용도에 아주 적합하다.
  • 만약, 두 개 이상의 객체에 tr1::shared_ptr이 하나씩 들어 있고 각각의 스마트 포인터가 이들 객체를 물고 있는 형태가 순환 구조를 이루고 있으면, 각 객체의 참조 카운트가 0이 안 될 수가 있다.
  • 이런 상황을 막기 위해 쓰는 것이 tr1::weak_ptr이다. tr1::shared_ptr에 기반한 비순환형 자료구조에서 순환고리를 가능하게 하는 포인터로 동작하게끔 설계되었다.
  • tr1::weak_ptr은 참조 카운팅에는 가담하지 않는다. 어떤 객체를 물고 있는 마지막 tr1::shared_ptr이 소멸될 때, tr1::weak_ptr이 여전히 계속해서 그 객체를 가리키고 있더라도 그 객체는 삭제된다. 단, 이 경우의 tr1::weak_ptr은 무효상태(invalid)로 표시된다.

tr1::function

  • 어떤 함수가 가진 시그니처와 호환되는 시그니처를 갖는 함수호출성 객체(callable entity)의 표현을 가능하게 해 주는 템플릿이다.
  • 시그니처가 비슷하면 호출이 가능한 일반화 콜백 함수를 만들어 보자는 것이 주요 개념이다.
  • 보통, int를 받고 string을 반환하는 콜백 함수를 등록하도록 만들고 싶으면 다음과 같이 한다.
// int를 받고 string을 반환하는 함수가 매개변수 타입
void registerCallback(std::string func(int));
  • 매개변수 이름으로 쓰인 func는 사실 없어도 되는 선택사항이므로, 다음과 같이 이름을 떼고 선언해도 문제가 없다.
void registerCallback(std::string (int));
  • 여기서 매개변수 타입에 해당하는 std::string(int) 부분이 바로 함수 시그니처이다.
  • 이런 용도에 tr1::function 템플릿을 사용하면 registerCallback 함수가 훨씬 융통성 있게 만들어진다.
  • 함수 시그니처 대신에 임의의 함수호출성 개체를 받도록 만들게 함으로써, int 타입 혹은 int로 변환이 가능한 어떤 타입도 전달받으며, string 타입 혹은 string으로 변환이 가능한 어떤 타입도 반환할 수 있는 그런 함수를 registerCallback의 매개변수로 설정할 수 있게 된다.
  • tr1::function의 템플릿 매개변수로는 앞의 그 시그니처를 넘긴다.
// 매개변수 func는 이제 std::string(int)와 호환되는 시그니처를 갖는
// 어떤 함수호출성 개체도 될 수 있다.
void registerCallback(std::tr1::function<std::string(int)> func);

tr1::bind

  • 현역 STL 바인더로 잘 쓰이고 있는 bind1st 및 bind2nd와 똑같이 동작함은 물론, 그보다 훨씬 더 많은 기능이 있는 범용 바인더이다.

  • TR1 이전의 바인더들과 달리, tr1::bind 함수는 상수 멤버 함수 및 비상수 멤버 함수에 상관없이 동작한다. 또한 참조로 전달되는 매개변수에 대해서도 동작한다.

  • 외부 보조 없이도 함수 포인터를 자체적으로 다룰 수 있기 때문에, tr1::bind를 호출하기 전에 ptr_fun, mem_fun 혹은 mem_fun_ref를 우겨 넣는 난리 부르스를 출 필요가 없다.

  • TR1의 나머지 구성요소는 두 종류로 나누어 소개한다. 우선, 단독으로 딱딱 끊어지는 기능을 제공하는 종류부터 알아보자.

해시 테이블(hash table)

  • 새로운 동작 원리로 무장한 연관 컨테이너 군단, 즉 set, multiset, map, multimap을 구현하는 데 이 해시 테이블이 쓰였다.
  • 이들 각각의 인터페이스는 똑같은 이름을 가진 TR1 이전의 연관 컨테이너의 인터페이스를 본떠서 만들어졌다.
  • TR1 해시 테이블 기반 컨테이너는 unordered_map, unordered_multimap, unordered_set, unordered_multiset이라는 이름을 가지고 있는데, 이는 해시 기반 컨테이너이기 때문에 원소가 저장되는 순서를 예측할 수 없다는 점을 강조하고 있다.
    • 기존은 map, multimap, set, multiset이라는 이름을 가지고 있다.

정규 표현식(regex expression)

  • 정규 표현식 기반의 탐색과 문자열에 대한 대체 연산이 가능하며, 일치되는 원소들 사이의 순회도 지원한다.

투플(tuple)

  • 종래의 표준 라이브러리에 원래 있었던 pair 템플릿의 신세대 버전이다.
  • pair 객체의 경우에는 두 개만 담을 수 있었지만, tr1::tuple 객체는 몇 개라도 담을 수 있다.

tr1::array

  • begin 및 end 등의 멤버 함수를 지원하는 배열이다.
  • tr1::array 객체의 크기는 컴파일 과정에서 고정된다.(동적 메모리를 쓰지 않는다.)

tr1::mem_fn

  • 멤버 함수 포인터를 적응시키는(adapt) 용도에 쓸 수 있는, 문법적으로 C++98의 mem_fun 및 mem_fun_ref를 그대로 껴안음과 동시에 기능을 확장한 템플릿이다.

tr1::reference_wrapper

  • 기존의 참조자가 객체처럼 행세할 수 있도록 만들어 주는 템플릿이다.
  • 이것을 사용하면 참조자를 담은 것처럼 동작하는 컨테이너를 만들 수 있다.(사실 컨테이너는 객체 혹은 포인터만 담을 수 있다.)

난수 발생

  • C++가 C 표준 라이브러리로부터 물려받은 rand 함수보다 몇 배는 우수한 난수 발생 기능이다.

특수 용도의 수학 함수

  • 라게르 다항식, 베셀 함수, 완전 타원 적분 등이며 그 외에도 많이 있다.

C99 호환성 확장 기능

  • C99의 새로운 라이브러리를 C++로 가져올 목적으로 설계된 함수 및 템플릿 모음

  • 나머지 TR1 구성요소의 두 번째 부분은 더 세련된 템플릿 프로그래밍 기법, 이를테면 템플릿 메타프로그래밍 같은 기법을 지원하는 기술들이다.

타입 특성정보(type traits)

  • 주어진 타입에 대한 컴파일 타임 정보를 제공하는 특성정보 클래스의 모음이다.
  • 어떤 T라는 타입에 대해 TR1의 타입 특성정보 기능을 적용하면, T가 기본제공 타입인지, 가상 소멸자를 지원하는지, 공백 클래스인지, 다른 U 타입으로 암시적 변환이 가능한지 등의 정보를 들추어낼 수 있다.
  • 심지어 주어진 타입의 적절한 바이트 정렬까지 잡아내어 준다.
  • 사용자 정의 메모리 할당 함수를 제작하는 프로그래머에게는 희소식이다.

tr1::result_of

  • 어떤 함수 호출의 반환 타입을 추론해주는 템플릿이다.

  • 템플릿을 만들다 보면 어떤 함수(템플릿)의 호출로 인해 반환되는 객체의 타입을 참조할 수 있으면 좋겠다는 생각이 꽤 자주 들지만, 반환 타입은 그 함수의 매개변수 타입에 따라 달라질 수 있다.

  • tr1::result_of 템플릿을 쓰면 함수 반환 타입을 쉽게 참조할 수 있다.

  • 이 템플릿은 TR1 자체적으로도 여러 군데에서 사용하고 있다.

  • TR1 구성요소들 중에는 TR1 이전의 구성요소들 몇 개에 대해서 기능을 그대로 끌어안은 것들이 있긴 하지만(tr1::bind와 tr1::mem_fn이 대표적이다.), 현재의 TR1은 그저 표준 라이브러리에 대한 부가 구성요소일 뿐이다.

  • 기존의 구성 요소 대신에 TR1이 쓰일 수 있다는 이야기가 절대로 아니므로, TR1 이전의 것을 써서 만든 재래식 코드는 그대로 유효하다.

  • 또한, TR1 자체는 그냥 문서이다. 이 문서에 명시된 기능을 맛보려면, 문서의 내용을 실제로 구현한 코드를 구해야 한다.

  • 결국 TR1 코드는 컴파일러와 짝을 이루어 제공될 것이다.

  • 사용하고 있는 표준 라이브러리 구현에서 TR1 구성요소를 찾으려고 하면 몇 개가 빠져 있을 수도 있다.

    • 이런 경우에는 TR1의 구성요소 중 10개는 부스트에서 무료로 공개한 라이브러리를 기반으로 한 것이라서, TR1스러운 기능을 맛보는 데는 부스트가 가장 좋은 자원이라 할 수 있다.
    • 물론 부스트의 것과 TR1의 명세가 완전히 맞지 않는 부분도 존재하기 때문이다.
  • 컴파일러에서 TR1 구현을 자체적으로 지원하지 않고 있어 임시변통으로 부스트의 TR1스러운 라이브러리를 써볼려면 꼼수를 부려야 한다.

  • 부스트 라이브러리에 속한 모든 구성요소는 boost 네임스페이스에 들어 있지만, TR1 구성요소는 std::tr1에 들어 있어야 하는 규칙이 있다.

  • 따라서 컴파일러에게 std::tr1에 대한 참조를 boost에 대한 참조로 처리해 달라고 부탁해야 한다.

namespace std {
    // std::tr1 네임스페이스는 이제 boost 네임스페이스의 별칭으로 설정된다.
    namespace tr1 = ::boost;
}
  • 기술적으로 볼 때, 이러한 꼼수를 부렸을 때의 결과는 정의되어 있지 않다.

  • 그 이유는 std 네임스페이스에는 일개 사용자 수준에서 어떤 것도 추가할 권한이 없기 때문이다.

  • 이론적으로는 그렇지만, 실제로는 아무런 사고도 안 날 가능성도 있다.

  • 컴파일러에서 자체적으로 TR1을 제공한다면 위의 별칭을 없애면 된다.

  • 부스트 라이브러리에 뿌리를 두고 있지 않은 TR1의 구성요소 중 가장 중요한 부분을 꼽는다면 아마 해시 테이블일 것이다.

  • 해시 기반 컨테이너는 과거에도 몇 군데에서 내놓은 제품을 통해 어렵지 않게 접할 수 있을 것이다.

항목 55: Boo자유친! 부스트를 늘 여러분 가까이에

  • 부스트는 C++ 개발자들의 단체이자 무료 다운로드가 가능한 C++ 라이브러리 집합을 동시에 일컫는 고유명사이다.

  • http://boost.org 에서 관련 정보를 만날 수 있다.

  • 부스트는 다른 곳에서는 따라올 수 없는 차별점이 두 개나 있다.

  • 첫째, 부스트는 C++ 표준화 위원회와 밀접하고 영향력 있는 밀월관계를 유지하고 있는 곳으로 유일하다.

    • 원래부터 위원회에 속해 있던 회원들 몇 명이 세운 곳이다.
    • 위와 같은 이유로 이름만 들어도 알 법한 유명한 분들이 부스트 및 현재의 표준화 위원회에 양다리를 걸치고 있는 경우가 정말 많다.
    • 부스트가 세워진 이래로 꾸준히 지켜왔던 활동목표들 중 하나가 표준 C++에 추가될 수 있는 기능들의 시험 장소로 바치는 것이었고, 그 노력이 결실을 맺어, TR1에서 추가된 14개의 라이브러리 중 무려 3분의 2 이상이 이미 부스트에서 배포하고 있는 것들이다.
  • 둘째, 라이브러리 승인 과정이다.

    • 부스트의 승인 과정은 공개 동료 심사에 기반을 두고 있다.
    • 자신이 만든 라이브러리를 부스트에 한 번 내 보고 싶다면, 일단 부스트 개발자 메일링 리스트에 글을 올려서 라이브러리가 얼마나 관심을 끄는지 알아본다.
    • 어느 정도 됐다 싶으면 사전 검사가 시작되는데, 부스트 사이트에서 말하는 토론-수정-다시 제출 이 과정을 만족할 때까지 반복의 고리를 돌게 된다.
    • 이 과정이 끝나면 라이브러리를 공식적으로 제출하기 위한 형식을 갖추게 되는데, 이때 심사 관리자가 라이브러리가 부스트의 최소 요구사항을 만족하는지를 확인해 준다.
      • 부스트 라이브러리가 되려면 일단 컴파일이 되는 컴파일러가 최소한 두 개는 되어야 한다.
      • 일정한 라이센스에 따라서 배포할 수 있는지의 여부 입증
    • 이 과정이 끝나면 비로소 여러분의 것이 부스트의 쟁쟁한 개발자 모임에 공식 심사 대상으로 제출된다.
    • 심사는 제출물(소스 코드, 설계 문서, 사용자 문서 등)을 검토하면서 다음과 같은 사항에 중점을 두어 진행된다.
      • 설계와 구현이 얼마나 우수하게 되어 있나?
      • 다른 컴파일러와 운영체제들에 맞추어 이식할 수 있는 코드인가?
      • 대상 사용자들, 다시 말해 이 라이브러리가 도움을 줄 수 있는 특정 분야 종사자에게 쓸모 있는 라이브러리인가?
      • 문서화가 명료하고, 완전하고, 정확하게 되어 있는가?
    • 각각에 대한 의견을 담은 심사 결과는 부스트 메일링 리스트를 통해 공개적으로 올라온다.
    • 그렇기 때문에 심사를 진행하는 당사자와 그 외의 사람들이 그 심사 결과를 보고 다른 의견을 나눌 수도 있게 된다.
    • 심사 기간이 끝날 무렵이 되면, 심사 관리자는 그간의 의견을 취합하여 여러분의 라이브러리에 대해 승인, 조건부 승인, 기각을 결정한다.
  • 이러한 동료 심사 시스템 덕택에 함량 미달의 라이브러리가 부스트에 발을 들여 놓는 일이 효과적으로 차단되었을 뿐만 아니라, 라이브러리를 한 번 제대로 만들어 보고 싶은 사람들에게 업계 수준의 교차 플랫폼 라이브러리를 설계, 구현하고 문서화하는 방법이 자연스럽게 전수되는 효과를 낳았다.

  • 부스트의 이름하에 배포되는 라이브러리로서 승인이 되려면 최소한 두 번 이상의 공개 심사는 기본이라는 것이 이 동네의 상식이다.

  • 부스트의 라이브러리 군단은 크게 십수 개의 범주로 나뉘어 있는데, 각각을 소개하면 다음과 같다.

문자열 및 텍스트 처리

  • 주요 구성요소로 타입 안전성을 갖춘 printf 비슷한 서식화 기능, 정규 표현식 및 토큰화와 구문분석 기능이 있다.

컨테이너

  • STL 양식의 인터페이스를 제공하는 고정 크기 배열, 가변 크기 비트세트, 다차원 배열 등이 포함되어 있다.

함수 객체 및 고차 프로그래밍

  • TR1의 기능을 구현하는 데 사용된 몇 개의 기반 라이브러리가 여기에 해당된다.
  • 람다 라이브러리는 별도의 준비 없이 즉석에서 함수 객체를 생성해 주는 기막힌 기능을 제공하는데, 여러분 자신도 무엇을 했는지를 자각하지 못할 정도로 감쪽같다.
using namespace boost::lambda; // boost의 lambda 기능을 쓸 수 있도록 만듬
std::vector<int> v;

// v안에 들어 있는 각각의 원소 x에 대해 x*2+10을 출력한다.
// _1은 람다 라이브러리에서 사용하는 '현재 원소'를 뜻하는 자리채움자이다.
std::for_each(v.begin(), v.end()),
                            std::cout << _1 * 2 + 10 << "\\n");

일반화 프로그래밍

  • 텍사스 소떼처럼 득실득실한 특성정보(traits) 클래스를 만날 수 있다.

템플릿 메타프로그래밍(TMP)

  • 컴파일 타임 단정문, 부스트 MPL 라이브러리 등이 여기에 포함된다.
  • MPL에는 아주 감동적인 물건들이 많지만 그 중 하나를 꼽는다면 타입 등의 컴파일 타임 개체를 STL스러운 자료구조로 관리할 수 있도록 지원한다는 것이다.
// 세 개의 타입(float, double, long double)을 담는 컴파일 타임
// 컨테이너를 list 비슷하게 만들고, 이것을 'floats'라고 부른다.
typedef boost::mpl::list<float, double, long double> floats;

// 기존의 'floats'에 들어 있는 타입 집합은 물론이고 그 집합의 앞에 int가 삽입된
// 새로운 타입 리스트를 만들고, 이것을 'types'라고 부른다.
typedef boost::mpl::push_front<floats, int>::type types;
  • 타입을 담아 관리할 수 있는 이런 컨테이너는 타입리스트라고 알려져 있다.

수학 및 수치 조작

  • 유리수, 4원수 및 8원수, 최대 공약수 및 최소 공배수, 난수 등이 포함된다.

정확성 유지 및 테스트

  • 암시적 템플릿 인터페이스를 형식화해 주는 라이브러리와 테스트 우선 프로그래밍을 가능하게 해 주는 라이브러리가 있다.

자료구조

  • 타입 안전성을 갖춘 공용체, 그리고 TR1에서 지원하는 것의 뿌리격인 바로 그 투플 라이브러리가 이 범주에 들어간다.

타 언어와의 연동 지원

  • C++와 파이썬 사이의 걸림돌 없는 상호운용을 가능하게 하는 라이브러리도 지원한다.

메모리

  • 고성능의 고정 크기 할당자를 지원하는 풀(Pool) 라이브러리. TR1에도 일부 포함된 가지각색의 스마트 포인터가 이 범주에 들어간다.
  • TR1에 들어가지 않은 스마트 포인터 중 하나가 scoped_array이다. 동적으로 할당된 배열에 대해 동작하는 auto_ptr 같은 스마트 포인터라고 보면 된다.

기타

  • CRC 점검, 날짜 및 시간 조작, 파일 시스템 횡단 등을 지원하는 라이브러리가 주요 구성요소이다.

  • 이렇듯 부스트에서 배포하는 라이브러리는 정말 많은 일을 도와주고 있다.

메모

항목 54: TR1을 포함한 표준 라이브러리 구성요소와 편안한 친구가 되자

  • 최초에 상정된 표준 C++ 라이브러리의 주요 구성요소는 STL, iostream, 로케일 등이다. 여기에는 C98의 표준 라이브러리도 포함되어 있다.
  • TR1이 도입되면서 추가된 것은 스마트 포인터(tr1::shared_ptr 등), 일반화 함수 포인터(tr1::function), 해시 기반 컨테이너, 정규 표현식 그리고 그 외의 10개 구성요소이다.
  • TR1 자체는 단순히 명세서일 뿐이다. TR1의 기능을 사용하기 위해서는 명세를 구현한 코드를 구해야 한다. TR1 구현을 구할 수 있는 자료처 중 한 군데가 바로 부스트이다.

항목 55: Boo자유친! 부스트를 늘 여러분 가까이에

  • 부스트는 동료 심사를 거쳐 등록되고 무료로 배포되는 오픈 소스 C++ 라이브러리를 개발하는 모임이자 웹사이트이다. 또한 C++ 표준화에 있어서 영향력 있는 역할을 맡고 있다.
  • 부스트에서 배포되는 라이브러리들 중엔 TR1 구성요소에 들어간 것도 있지만, 그 외에 다른 라이브러리들도 아주 많다.

'책 > 이펙티브 C++' 카테고리의 다른 글

이펙티브 C++(370p ~ 381p)  (1) 2024.02.14
이펙티브 C++(360p ~ 369p)  (0) 2024.02.13
이펙티브 C++(350p ~ 361p)  (1) 2024.02.12
이펙티브 C++(340p ~ 350p)  (1) 2024.02.10
이펙티브 C++(332p ~ 340p)  (1) 2024.02.09
    '책/이펙티브 C++' 카테고리의 다른 글
    • 이펙티브 C++(370p ~ 381p)
    • 이펙티브 C++(360p ~ 369p)
    • 이펙티브 C++(350p ~ 361p)
    • 이펙티브 C++(340p ~ 350p)
    readme.md
    readme.md

    티스토리툴바