#1. [모던 C++ STL] 주요 구성 요소 미리보기(C++11, C++14, C++17, C++20)
모던 C++ STL은 모던 C++의 변경에 맞춰 다음의 라이브러리들이 모두 개선되고 추가되었습니다.(모던 C++의 변경 내용은 [모던 C++] 주요 구성 요소 미리보기(C++11, C++14, C++17, C++20)를 참고하시기 바랍니다.)
모던 C++ STL은 모던 C++의 변경에 맞춰 다음의 라이브러리들이 모두 개선되고 추가되었습니다.(모던 C++의 변경 내용은 [모던 C++] 주요 구성 요소 미리보기(C++11, C++14, C++17, C++20)를 참고하시기 바랍니다.)
(C++11~) nullptr_t가 추가되었습니다. (C++11~) lldiv_t, lldiv_t, imaxdiv_t, float_t, double_t가 추가되었습니다. (C++11~) LLONG_MIN, LLONG_MAX가 추가되었습니다. (C...
(C++11~) get_new_handler()가 추가되었습니다. (C++11~) pointer_traits가 추가되어 포인터와 유사한 타입들을 다루는 표준화된 방법을 제공합니다. (C++11~) aligned_alloc()이 추가되어 정렬된 메모리를 ...
(C++11~) tuple이 추가되어 다수의 요소를 관리할 수 있는 데이터 전달용 개체를 좀 더 간편하게 만들 수 있습니다. (C++11~) move()가 추가되어 좌측값을 우측값으로 형변환할 수 있습니다. (C++11~) move_if_noexcept...
[MEC++#13] iterator 보다 const_iterator를 선호하라.(const_iterator 지원 참고) [MEC++#42] 기존 push_back()등의 삽입 대신 emplace_back()등의 삽입을 고려하라.(emplace(), emplac...
(C++11~) move_iterator 어뎁터가 추가되어 이터레이터가 가리키는 요소를 이동 연산 할 수 있습니다. (C++11~) make_move_iterator가 추가되었습니다. (C++11~) next()와 prev()가 추가되었습니다. ...
(C++11~) all_of(), any_of(), none_of(), find_if_not()이 추가되었습니다. (C++11~) minmax(), minmax_element()가 추가되었습니다. (C++11~) is_heap(), is_heap_unt...
(C++11~) 기존에 제공되던 함수자 타입 특성 클래스(unary_function, binary_function등), 바인더(bind1st(), bind2nd()등), 어뎁터와 부정자(mem_fun(), mem_fun_ref(), ptr_fun(), not1(), ...
(C++11~) u16string이 추가되어 UTF-16 인코딩 문자열을 지원합니다. (C++11~) u32string이 추가되어 UTF-32 인코딩 문자열을 지원합니다. (C++11~) isblank()가 추가되었습니다. (C++11~) ato...
(C++11~) complex에 proj()이 추가되었습니다. (C++11~) 공통 수학 함수가 보강되었습니다. (C++11~) 부동 소수점 환경이 추가되었습니다. (C++11~) 난수 생성기가 추가되어 다양한 형태의 난수를 만들 수 있습니다. ...
(C++11~) vscanf(), snprintf(), vsnprintf()가 추가되었습니다. (C++11~) hexfloat(), defaultfloat(), get_money(), put_money(), get_time(), put_time()이 추가되었습...
(C++11~) isblank()가 추가되었습니다. (C++11~C++17) 문자열 현지화 변환(wstring_convert, wbuffer_convert, codecvt_utf8, codecvt_utf16, codecvt_utf8_utf16, codecvt_...
(C++11~) 동적 예외 사양이 deprecate 되면서 unexpected()도 함께 deprecate 되었습니다. (C++11~) future_error, regex_error, system_error, ios_base::failure, bad_weak_...
(C++11~) type_traits가 추가되어 컴파일 타임 프로그래밍시 각 타입의 조건들을 검사하거나 타입 변환을 할 수 있습니다. (C++14~) is_null_pointer, is_final이 추가되었습니다. (C++17~) bool_constan...
(C++11~) ratio가 추가되어 소수점 오차없이 유리 분수를 표현할 수 있습니다. 분자와 분모를 따로 저장하여 유리 분수를 표현하며, 유틸리티들을 이용하여 컴파일 타임 유리수(정수와 분수) 연산을 지원합니다.
[MEC++#18] 소유권 독점 자원의 관리에는 unique_ptr를 사용하라.(unique_ptr 참고) [MEC++#22] PImpl 관용구를 사용할때에는 암시적으로 정의되는 특수 멤버 함수들을 구현 파일에서 정의하라.(unique_ptr을 이용한 PImp...
[MEC++#19] 소유권 공유 자원의 관리에는 shared_ptr을 사용하라.(shared_ptr 참고) new한 포인터를 직접 사용하지 마라.(shared_ptr 소유권 분쟁 참고) [MEC++#20] sha...
(C++11~) system_clock, time_point, duration 이 추가되어 좀더 다양한 정확도로 시간을 추적할 수 있습니다. (C++17~) floor(), ceil(), round(), abs()가 추가되어 time_point와 duratio...
(C++11~) tuple이 추가되어 다수의 요소를 관리할 수 있는 데이터 전달용 개체를 좀 더 간편하게 만들 수 있습니다. (C++11~) make_tuple(), tie(), forward_as_tuple()이 추가되어 tuple을 쉽게 생성할 수 있습니다...
[MEC++#34] bind() 보다는 람다람다 표현식를 선호하라.(bind() 참고) 람다 표현식이 가독성이 좋다.
(C++11~) hash()가 추가되어 각 타입별로 데이터의 해시값(Digest)을 구할 수 있습니다.
(C++11~) array가 추가되어 기존 C스타일의 배열처럼 연속된 메모리를 사용하는 컨테이너를 제공합니다. C스타일 배열처럼 컴파일 타임에 크기가 결정되어 스택에 할당되므로, 힙에 할당되는 vector 보다 성능이 좋습니다. (C++20) to_array(...
(C++11~) forward_list가 추가되어 단방향 리스트를 제공합니다. 기존 양방향 리스트인 list보다 요소 관리 공간을 작게 차지하며, push_front()로 요소의 앞쪽 방향으로 리스트를 구성합니다.
(C++11~) unordered_map, unordered_multimap, unordered_set, unordered_multiset가 추가되어 해시값(Digest)을 사용하는 정렬되지 않은 컨테이너를 제공합니다. (C++17~) insert_or_ass...
[MEC++#16] 상수 멤버 함수를 쓰레드에 안전하게 작성하라. mutable인 경우 mutex를 사용하라. [MEC++#37] thread 들을 모든 경로에서 합류 불가능하게 만들어라.(thread 참고) ...
(C++11~) condition_variable이 추가되어 쓰레드간 동기화를 위해 쓰레드를 wait()시킨뒤, 특정 조건이 되었을때 활성화 시킬 수 있습니다.
[MEC++40] 동시성에는 atomic을 사용하고, volatile은 최적화를 하면 안되는 특별한 메모리에 사용하라.(atomic, volatile 참고)
[MEC++#35] thread 기반 프로그래밍 보다 async() 기반 프로그래밍을 사용하라.(async() 참고) 코드가 간결하다. [MEC++#36] 비동기성이 필수일 때에는 launch::async를 지정...
(C++11~) regex_match()가 추가되어 문자열의 전체가 정규 표현식과 일치하는지 검사할 수 있습니다. (C++11~) regex_search()가 추가되어 문자열의 일부가 정규 표현식과 일치하는지 검사할 수 있습니다. (C++11~) reg...
(C++14~) integer_sequence가 추가되어 컴파일 타임에 정수 타입의 시퀀스를 만들 수 있습니다.
(C++14~) exchange()가 추가되어 주어진 값을 바꾸는 작업이 간편해 졌습니다. 특히 이동 생성자와 이동 대입 연산자 구현에 활용할 수 있습니다.
(C++14~) 표준 사용자 정의 리터럴이 추가되어 operator ""s, operator ""min, operator ""if, 등 문자열, 날짜 / 시간, 복소수 관련 표현이 간편해 졌습니다. (C++17~) operator ““sv가 추가되어 strin...
(C++17~) optional이 추가되어 값이 있을 수도 있고, 없을 수도 있는 데이터를 처리할 수 있어, 미확정 상태, 값을 처리하기 부적절한 상태, 함수 리턴값 성공 여부 처리를 좀더 단순하게 할 수 있습니다.
(C++17~) any가 추가되어 타입의 변동 가능성이 있는 데이터를 비교적 안전하게 사용할 수 있습니다.
(C++17~) variant가 추가되어 타입이 다른 여러 데이터들을 동일한 메모리 공간에서 쉽게 관리할 수 있습니다.
(C++17~) string_view가 추가되어 문자열을 읽기 전용으로 사용할 때 불필요한 문자열 복제가 없도록 해줍니다. (C++20~) u8string_view가 추가되었습니다.
(C++17~) 대부분의 알고리즘에서 병렬 작업을 지원하는 함수 오버로딩 버전이 추가되었습니다. seq, par, par_unseq으로 병렬 실행 정책을 지정할 수 있습니다. (C++20~) unseq가 병렬 실행 정책에 추가되었습니다.
(C++17~) polymorphic_allocator가 추가되어 할당시 런타임 다형성을 지원합니다. 메모리 리소스를 사용하여 메모리 풀을 손쉽게 만들 수 있습니다. (C++20~) allocate_bytes(), deallocate_bytes()등이 추가되어...
(C++17~) path, absolute(), relative()등이 추가되어 경로 문자열을 생성할 수 있습니다. (C++17~) current_path(), directory_iterator(), recursive_directory_iterator()등이 ...
(C++20~) same_as, derived_from, convertible_to, integral, floating_point, assignable_from, swappable, destructible, constructible_from, default_initi...
(C++20~) coroutine_handle 이 추가되어 코루틴을 재개하는 코루틴 핸들을 제공합니다. (C++20~) suspend_always, suspend_never가 추가되어 코루틴에서 사용하는 대기 가능 개체를 제공합니다. (C++20~) c...
(C++20~) 범위(Range)가 추가되어 이터레이팅할 수 있는 추상적인 요소들을 처리할 수 있습니다. (C++20~) 포인트 개체인 ranges::begin, ranges::end등이 추가되어 범위(Range)의 이터레이터를 구할 수 있습니다. (C...
(C++20~) span이 추가되어 C스타일 배열, array, vector, 메모리, string 등 연속된 메모리 시퀀스를 참조할 수 있습니다.
(C++20~) format(), format_to(), format_to_n()이 추가되어 %d, %s 처럼 간편하고, << 처럼 확장성 있는 서식화 방법을 지원합니다. (C++20~) 표준 서식 지정자가 추가되어 채움, 정렬, 부호, 너비, 정밀...
모던 C++ 은 현대적인 언어 특성에 발맞춰 좀더 단순하게 코딩할 수 있도록 개선되었습니다.(모던 C++ STL의 변경 내용은 [모던 C++ STL] 주요 구성 요소 미리보기를 참고하시기 바랍니다.)
[MEC++#8] 0과 NULL 보단 nullptr를 선호하라.(nullptr 참고) [MEC++#9] typedef 보다 using을 이용한 타입 별칭을 선호하라.(클래스 템플릿 별칭 참고)
(C++11~) 사용자 정의 리터럴이 추가되어 int operator ""_km(long double val);와 같이 사용자가 정의해서 사용할 수 있으며, 단위계 처리가 쉬워졌습니다. (C++20~) 사용자 정의 리터럴 인자 규칙에 char8_t이 추가되었습...
(C++11~) 인라인 네임스페이스가 추가되어 API 버전 구성이 편리해 졌습니다. (C++17~) 단순한 중첩 네임스페이스가 추가되어 :: 로 표현할 수 있습니다. (C++20~) 인라인 네임스페이스와 단순한 중첩 네임스페이스를 결합하여 표시할 수 있...
[MEC++#7] 객체 생성시 괄호와 중괄호를 구분하라.(인자의 암시적 형변환 차단, 기존 생성자와 initializer_list 생성자와의 충돌 참고)
(C++11~) 범위 기반 for()가 추가되어 컨테이너 요소의 탐색 처리가 쉬워졌습니다. (C++17~) 초기식을 포함하는 if(), switch()가 추가되어 함수 리턴값을 평가하고 소멸하는 코드가 단순해 졌습니다. (C++20~) 범위 기반 fo...
[MEC++#11] 정의되지 않은 비공개 함수보다 delete된 함수를 선호하라.(delete를 이용한 암시적 형변환과 템플릿 인스턴스화 차단 참고) [MEC++#12] 재정의 함수들을 override로 선언하라.(override 참고)
(C++11~) explicit 형변환 연산자가 추가되어 명시적으로 형변환 할 수 있습니다. (C++20~) explicit(bool)이 추가되어 특정 조건일 때만 explicit로 동작하게 할 수 있습니다.
[MEC++#14] 예외를 방출하지 않을 함수는 noexcept로 선언하라.(느슨한 noexcept 계약 참고) noexcept는 최적화 여지가 크다. 이동 생성자, 이동 대입 연산자, swap(), 소멸자는 noexcept로 만들어라. ...
[MEC++#1] 함수 템플릿 인수 추론을 숙지하라.(함수 템플릿 인수 추론 참고) 참조성은 제거된다. 배열은 포인터로 붕괴된다. 함수는 함수 포인터로 변경된다. 최상위 const 는 무시된다. ...
[MEC++#17] 암시적으로 정의되는 특수 멤버 함수들의 자동 작성 조건을 숙지하라.(이동 연산에 따른 암시적 정의 참고) [MEC++#29] 이동 연산이 존재하지 않고, 저렴하지 않고, 적용되지 않는다고 가정하라.(암시적 이동 연산 변환 참고) ...
(C++11~) 멤버 함수 참조 지정자가 추가되어 멤버 함수에 &, && 로 좌측값에서 호출될때와 우측값에서 호출될 때를 구분하여 함수 오버로딩을 할 수 있습니다.
[MEC++#23] move()와 forward()를 숙지하라.(move 원리, 상수 개체의 move(). forward() 와 완벽한 전달, forward() 원리 참고) [MEC++#24] 전달 참조와 우측값 참조를 구별하라.(전달 참조 참고) [M...
[MEC++#10] 범위 없는 열거형보다 범위 있는 열거형을 선호하라.(열거형의 암시적 형변환, 전방 선언, 기반 타입 참고)
(C++11~) 무제한 공용체가 추가되어 공용체 멤버에서 생성자/소멸자/가상 함수 사용 제한이 풀렸으며, 메모리 절약을 위한 코딩 자유도가 높아졌습니다.
[MEC++#31] 기본 람다 캡쳐 모드를 피하라.(람다 캡쳐 참고) 람다 캡쳐하는 항목을 나열하는게 직관적이다. [=]는 this를 람다 캡쳐한다. [MEC++#32] 객체를 클로저 안으로 이동시...
(C++11~) static_assert()가 추가되어 컴파일 타임 진단이 가능해 졌습니다. (C++17~) static_assert()의 메시지 생략을 지원합니다.
[MEC++#15] 가능하면 항상 constexpr을 사용하라.(constexpr 함수 참고) constexpr 함수는 컴파일 타임, 런타임 모두 사용할 수 있다.
(C++11~) extern으로 템플릿 선언을 할 수 있으며, 템플릿 인스턴스 중복 생성을 없앨 수 있습니다. (C++11~) 템플릿 오른쪽 꺽쇠 괄호 파싱을 개선하여 템플릿 인스턴스화시 >가 중첩되어 >>와 같이 되더라도 공백을 추가할 필요가...
(C++11~) 가변 템플릿과 파라메터 팩이 추가되어, 가변 인자(…)와 같이 갯수와 타입이 정해 지지 않은 템플릿 인자를 사용할 수 있습니다. (C++11~) sizeof…() 연산자가 추가되어 가변 템플릿에서 파라메터 팩의 인자수를 구할 수 있습니다. ...
(C++11~) 특성(attirbute)이 추가되어 컴파일러에게 부가 정보를 전달하는 방식을 표준화 했습니다. (C++14~) [[deprecated]]가 추가되어 소멸 예정인 것을 컴파일 경고로 알려줍니다. (C++17~) [[fallthrough]]...
(C++17~) 임시 구체화와 복사 생략 보증을 통해 컴파일러 의존적이었던 생성자 호출 및 함수 인수 전달 최적화, 리턴값 최적화등이 표준화 되었습니다.
(C++17~) 인라인 변수가 추가되어 헤더 파일에 정의된 변수를 여러개의 cpp에서 #include 하더라도 중복 정의 없이 사용할 수 있습니다. 또한, 클래스 정적 멤버 변수를 선언부에서 초기화 할 수 있습니다.
(C++17~) 구조화된 바인딩이 추가되어 배열, pair, tuple, 클래스등의 내부 요소나 멤버 변수에 쉽게 접근할 수 있습니다.
(C++20~) 삼중 비교 연산자가 추가되어 비교 연산자 구현이 간소화 되었습니다. (C++20~) 삼중 비교 연산자를 default로 정의할 수 있습니다. (C++20~) 비트 쉬프트 연산자의 기본 비트가 표준화되어 << 1는 곱하기 2의 ...
(C++20~) 컨셉(concept)과 요구사항(requires)이 추가되어 템플릿 인자나 auto에 제약 조건(constraint)을 줄 수 있습니다. (C++20~) 컨셉 설계를 활용하여 마치 인터페이스처럼 컨셉에 의한 코딩 계약을 만들 수 있습니다.
(C++20~) 모듈이 추가되어 전처리 사용 방식을 개선하여 컴파일 속도를 향상시키고, #include 순서에 따른 종속성 문제, 선언과 정의 분리 구성의 불편함, 기호 충돌 문제를 해결했습니다.
(C++20~) 코루틴이 추가되어 함수의 일시 정지 후 재개가 가능합니다.
(C++11~) alignas() 와 alignof()가 추가되어 메모리 정렬 방식을 표준화 됐습니다. (C++11~) 가변 매크로가 추가되어 C언어와의 호환성이 높아졌습니다. (C++11~) 멤버의 sizeof()시 동작이 개선되어 개체를 인스턴스화 ...
좋은 설계는 유지보수의 편의성을 위하여
단일 책임 원칙은 개체는 단 하나의 책임만 가져야 한다 는 원칙입니다.
개방-폐쇄 원칙은 확장에는 열려 있되, 수정에는 닫혀 있게 작성하라 라는 원칙입니다.
리스코프 치환 원칙은 자식 개체는 부모 개체를 완전하게 치환할 수 있어야 한다 는 원칙입니다.
인터페이스 분리 원칙은 클라이언트는 자신이 사용하지 않는 것에 강제로 의존하지 말아야 한다 는 원칙입니다.
의존성 역전 원칙은 상위 수준 모듈은 하위 수준 모듈에 의존하지 말아야 한다 는 원칙입니다.
캡슐화는 개체 사용자가 개체의 내부 상태의 구현 원리를 알 필요가 없게 하라 라는 원칙입니다.
명시적 의존성 원칙은 개체나 함수는 제대로 작동하는데 필요한 요소를 명시적으로 요청하라 라는 원칙입니다.
묻지 말고 말하라 원칙은 개체의 내부 정보를 자꾸 묻지 말고 그냥 원하는 작업을 시켜라 라는 원칙입니다.
헐리우드 원칙은 헐리우드 영화 제작사가 오디션 배우에게 전화하지 마세요. 연락처 주시면 우리가 전화드릴께요. 라고 안내한 말에서 유래된 원칙입니다.
제어의 역전 원칙은 외부 라이브러리의 제어를 따르라 라는 원칙입니다.
관심사의 분리 원칙은 구별되는 부분들로 분리시켜라 라는 원칙입니다.
안정적인 의존성 원칙은 패키지 간의 의존성은 안정성의 방향이어야 한다 라는 원칙입니다.
아키텍처 민첩성 원칙은 요구사항 변화에 적응할 수 있도록 아키텍처를 설계하라 는 원칙입니다.
보이 스카우트 규칙은 캠핑장은 처음 왔을 때보다 더 깨끗하게 하고 떠나라 라는 원칙입니다.
단순하게 유지하라는 원칙은 흔히 KISS(Keep It Simple, Stupid) 라고도 불립니다.
필요할때 구현하라는 항상 실제로 필요할때 구현해야 하며, 나중에 필요하다고 예상하고 미리 구현하지 마라 라는 원칙입니다.(앞글자를 따서 YAGNI 라고도 합니다.)
스스로 반복하지 마라 원칙은 추상화를 통해 논리의 중복을 제거하라 라는 원칙입니다. 흔히 DRY 라고도 불립니다.
한번 단 한번만 원칙은 “스스로 반복하지 마라” 와 같이 반복하지 말라는 원칙입니다.
불완전성의 허용은 아키텍처는 완전할 수 없으니 다양한 문제에 균형을 유지하라 라는 원칙입니다.
최소한의 놀라움 원칙은 사용자나 동료가 예측 가능하게 하라 라는 원칙입니다.
[좋은 코드] 집단 코드 소유권(Collective Code Ownership)
[나쁜 코딩 관행] 코드 냄새(Code Smells)
C++ 의 주요 구성 요소는 하기와 같습니다.
밑줄로 시작하지 말고, 이중 밑줄을 사용하지 마라. 헝가리안 표기법을 사용하지 마라. 매크로는 대문자로 작성하라. 이름을 반복하지 마라.
타입 크기에 의존하여 코딩하지 마라. OS에 따라, 컴파일러에 따라, 시스템 비트수에 따라 크기가 달라질 수 있다. 대소 비교가 필요한 경우에는 정수 타입을 사용하라. 실수 비교는 오차가 있다.
이름의 유효 범위는 짧게 유지하라. 중괄호({}) 블록으로 짧게 만들 수 있다.
이름 충돌을 피하기 위해 복잡한 접두어를 쓰지 말고, 네임스페이스를 사용하라. using 선언과 using 지시문 사용시 유효 범위가 커지지 않도록 주의하라.(전역 공간에 using namespace를 사용하면 망한다.)
BOOL보다는 bool을 사용하라.
포인터 보다는 참조자를 사용하라.(널검사가 필요없다.) 지역 변수의 참조자를 리턴하지 마라.(이미 소멸된 개체다.)
속도 성능에 영향이 없다면 유지보수시 확장성을 위하여 배열보다는 vector를 사용하라. 동적 요소 할당을 지원하며, 여전히 엑세스는 빠르다. new[]-delete[] 쌍을 준수하라.
5대 원칙(SOLID)정도는 사전에 숙지하고 구조체/클래스/공용체를 만들어라. 구조체와 클래스의 차이는 초기화 방법과 기본 접근 지정자(구조체는 public, 클래스는 private) 뿐이다. 공용체는 플랫폼에 따라, 컴파일러에 따라, 최적화 옵션에 따...
열거형은 클래스나 네임스페이스내에 정의하여 이름 유효 범위를 축소하라.
const 정확성을 지켜라. 무조건 const를 들이대라. 상수 개체와 상수 멤버 함수는 메모리를 수정하지 않기 때문에 예외가 발생하지 않는다.
변수의 수명(유효 범위)은 짧을 수록 좋다. 최대한 임시 개체나 지역 변수로 사용하라. 전역 변수나 정적 전역 변수 보다는 함수내 정적 지역 변수를 사용하라. 컴파일러 최적화가 쉽도록 임시 개체를 사용하라.
힙에 동적으로 메모리에 할당한 것은 명시적으로 소멸시켜라. 스택에 생성된 변수는 유효 범위가 종료되면 자동 소멸 된다.
생성하면서 초기화 하라. 초기화되지 않은 변수를 사용하지 마라. 자동 제로 초기화에 의존하지 마라. 낭패볼 수 있다.
문자열 상수를 많이 만들면, 프로그램 용량이 커진다. 비슷한 문장을 쓸데없이 여러개 작성하지 마라.
암시적 형변환은 실수하기 쉽게 만든다. 명시적으로 형변환하라. bool 형변환 연산자 정의는 하지 마라. 나아가 모든 타입의 형변환 연산자 정의를 하지 마라. 뜻하지 않게 몰래 암시적 형변환한다. 인자가 1개인 값 생성자는 explicit로 암시적 형변...
수정될 필요가 없는 문자열 데이터는 const char* 나 const wchar_t*로 관리하라.(배열이나 string, wstring을 쓰면 복제된다.) 멀티 바이트 문자열은 권장하지 않는다. 사용하지 마라. 소스 코드 저장시에는 다국어 처리에 적합...
임시 개체가 생성되지 않도록 이항 산술 연산자(a = a + b)보다는 산술형 대입 연산자(a += b)를 사용하라. 후위형 증감 연산자는 헷갈리고, 쓸데없는 임시 개체가 생성되니 사용하지 마라. 비교 연산 오버로딩은 <을 활용해서 구현하라.
코드 분석을 위해 제어의 중첩을 최소화 하라.(조건 상태표를 활용하라.) 예외에 안전할 수 있도록 사전 조건 검사를 수행하라. goto는 코드 분석을 방해하니 사용하지 마라.
동적 예외 사양을 사용하지 마라. 함수 포인터 대신 함수자 나 Strategy 패턴을 이용하라. 멤버 개체의 참조가 아니라면, 컴파일러 최적화가 쉽도록, 리턴값 최적화가 가능하도록, 리턴값은 값 타입으로 리턴하라. 다형적인 가상 함수에서 부모 개...
inline은 요청일 뿐이다. 컴파일러가 인라인화를 판단한다.
매크로 상수를 쓰지 말고 열거형 상수를 사용하라. 매크로로 타입의 별칭을 만들지 말고 typedef를 사용하라. 매크로 함수를 쓰지 말고 인라인 함수를 사용하라.
헤더 파일에서 다른 헤더 파일을 #include하는 것은 최소화 하라. 선언과 정의 분리, 전방 선언으로 컴파일 종속성을 최소화 하라.
Abstract Factory는 특정 그룹 계열에 속한 개체들을 생성합니다. 생성할 개체들이 일련의 그룹인 경우 생성 관련 로직을 간결하게 만들 수 있습니다.
Builder는 여러 요소가 합성된 개체일 경우 요소를 합성하는 방법과 요소를 생성하는 방법을 분리하여 확장성을 향상시켜 줍니다.
Factory Method는 생성에 대한 구체적인 정보를 자식 클래스에서 알고 있을때 부모 클래스에서 자식 클래스에게 생성을 요청하기 위해 사용합니다.
Prototype은 미리 정의된 개체로부터 복제하여 개체를 생성합니다. 속성까지 동일한 개체를 여러개 만들때 사용하면 좋습니다.
Singleton은 개체가 오직 1번만 생성된다는 것을 코딩 계약으로 보장합니다.
Adapter는 임의의 개체(Adpatee)를 기존 인터페이스로 사용하기 위해 감쌉니다. 개체의 소스코드를 직접 수정할 수 없을때 사용합니다.
Bridge는 추상과 구현을 분리하여, 종속적인 부분을 느슨하게 만들어 주거나, 구현을 다형적으로 만들 수 있게 합니다.
Composite은 단일 개체와 복합 개체를 추상화하여 모두 동일한 방식으로 다루게 해줍니다. 둘을 서로 구분하여 처리할 필요가 없어지기 때문에 고민할 것들이 줄어듭니다.
Decorator는 개체에 동적으로 새로운 외형을 추가하거나 기능을 추가할 때 포함을 통해 처리합니다. 클래스를 직접 수정하거나 상속을 이용하여 추가하는 것보다 코드가 간결해 집니다.
Facade는 서브시스템의 클래스들이 복잡하게 얽혀있고 사용이 어려운 경우, 단순하고 일관된 상위 수준의 통합 인터페이스를 제공합니다. 외부에서 내부 서브시스템을 몰라도 되므로, 사용하기 쉬워집니다.
Flyweight는 동일한 데이터가 반복해서 사용되는 경우 데이터를 공유하여 메모리 효율성을 향상시킵니다.
Proxy는 실제 개체의 동작을 대리해서 실행합니다. 최소한의 정보만을 이용하여 대리 실행하기 때문에, 생성이나 실행시 속도 부하가 있는 개체의 속도 개선을 위해 사용합니다.
Chain of Responsibility는 요청을 여러 개체에 전달하여 함께 처리할 수 있게 해줍니다. 한군데에서 모든 요청을 처리하지 않고 책임에 따라 여러 개체에 분산하므로, 해당 개체 구현시 고민할 것들이 줄어듭니다.
Command는 기능의 요청과 실행을 분리하여, 실행 부분이 재활용될 수 있게 합니다. 동일한 기능을 메뉴, 단축키, 매크로등 여러 방법으로 실행할 수 있을때 사용하면 좋습니다.
Interpreter는 비교적 단순하게 설계된 임의의 언어를 해석하는 간단한 방법을 제공합니다. 파서를 통해 가상의 트리를 만들고 이를 이용하여 구문을 해석합니다.
Iterator는 집합 개체에서 요소에 접근하는 방법을 제공합니다. 집합 개체의 내부 구현을 외부에 은닉하기 때문에 집합 개체의 구현 방식을 비교적 안전하게 변경할 수 있습니다. C++의 경우 STL의 컨테이너는 모두 이터레이터를 제공하며, begin(), end(), ++, * ...
Mediator는 개체들끼리의 상호작용을 캡슐화합니다. 개체들끼리 서로 직접 참조하지 않기 때문에 결합도가 낮아져 유지보수 편의성이 향상됩니다.
Memento는 내부 상태를 저장해 두고 나중에 복원할 수 있게 해줍니다. Command 패턴과 함께 사용되어 Undo를 구현할 수 있습니다.
Observer는 특정 개체를 감시하며, 변경 발생을 통지 받는 일반적인 구조입니다.(개체지향 원칙중 헐리우드 원칙과 유사합니다.)
State는 내부 상태에 따라 다른 동작 방법을 제공합니다. 상태를 처리하는 코드들이 응집되어 상태 처리가 비교적 단순해 집니다.
Strategy는 알고리즘이나 기능등의 전략을 캡슐화하고 런타임에 변경할 수 있게 만들어 줍니다. 외부에서 동작을 결정하고 변경할 수 있어 확장성이 향상됩니다.
Template Method는 부모 개체에서 대략의 뼈대를 구현하여 뼈대 동작을 정규화하고, 자식 개체에서는 최소의 구현만 하게 합니다.
Visitor는 개체를 수정하지 않고도 새로운 기능을 추가할 수 있게 합니다.
스마트 포인터로 인자의 의미를 선언하는 방법 리턴 선언 방법
< 만 구현하고 상속
if () 로 사전검사
소유권 이전을 할 것인지, 깊은 복제를 할 것인지, 자원을 공유할 것인지, 유일한 자원을 사용할 것
데이터 오버런(overrun) 및 언더런(underrun) 등 잘못된 힙 사용을 탐지하기 위해 탐지용 byte를 추가로 할당하는 경우(진단 참고)
동적 할당 메모리의 실제 사용에 관한 통계 정보를 수집하는 경우(개체 수명 로그 참고)
할당 및 해제의 효율을 향상시키기 위해 동적 메모리 오버헤드를 줄이고 메모리 관리를 직접 수행하는 경우(메모리 풀)
1 2 3 4 5 6 7 8 9 // 복사 생성과 복사 대입 연산을 할 수 없는 개체 class Uncopyable { protected: Uncopyable() {} // 상속해서만 사용 가능 ~Uncopyable() {} private: Uncopya...
1 2 3 4 5 6 7 8 // 스택만 할당할 수 있는 개체 class OnlyStackAssignable { protected: OnlyStackAssignable() {} // 상속해서만 사용 가능 ~OnlyStackAssignable() {} private:...
논리적으로는 데이터를 얻어오는 상수 멤버 함수이나, 실질적으로는 멤버 변수를 수정하는 함수가 있습니다. 주로 지연 생성이나 캐쉬를 구현하는 경우에 필요합니다.
new시 오류 발생시 처리하는 new_handler를 만들 수 있습니다.
RAII(Resource Acquisition Is Initialization)는 자원 획득은 초기화이다 라는 뜻입니다.
일반화 프로그래밍이 적합한 코드 구조를 억지로 인터페이스화 하지 마라.
템플릿은 템플릿 인스턴스화 하기 전에는 코드를 생성하지 않는다. 클래스, 함수, 멤버 함수, 중첩 클래스를 템플릿으로 만들 수 있다.
일반화 프로그래밍에서의 다형적 동작을 위해 템플릿 특수화, 템플릿 부분 특수화, 함수 템플릿 특수화, 함수 오버로딩을 이용하라. 함수 템플릿을 정의할때 함수 템플릿 오버로딩과 함수 템플릿 특수화의 순서를 지켜라.
종속 타입인 경우 typename, 템플릿 파싱 오류시 template을 작성하라.
함수 템플릿 오버로딩시에는 T보다는 T* 보다는 const T*가 선택된다. 연산자 오버로딩은 비멤버 함수 템플릿으로 작성하라. 함수 템플릿 인수 추론시 T&는 T로 추론된다.
타입 특성 클래스를 이용하여 템플릿 인자와 코딩 계약을 맺어라. 타입 특성 클래스를 이용하여 타입 처리 방식을 응집하라.
Standard Template Library(STL) 의 주요 구성 요소는 하기와 같습니다.
모던 C++ (C++11~) tuple이 추가되어 다수의 요소를 관리할 수 있는 데이터 전달용 개체를 좀 더 간편하게 만들 수 있습니다. (C++17~) 구조화된 바인딩이 추가되어 배열, pair, tuple, 클래스등의 내부 요소나 멤버 변수에 쉽게 접근...
삽입/삭제 성능, 검색 성능, 노드 구성 용량 부하를 검토하여 최적의 컨테이너를 선택하라. 컨테이너의 변경이 용이하도록 코딩하라. 컨테이너 종류나 사용하는 알고리즘에 따라 복사 생성자, 복사 대입 연산자, 비교 연산자를 구현하라.
컨테이너 멤버 함수 erase()와 알고리즘 remove() 함수의 차이를 알아둬라. 컨테이너는 삽입한 요소의 복제본을 관리한다. 원본을 관리하려면 포인터를 이용하라.
이터레이터는 전위 증가 연산자를 사용하라. for()를 이용하여 이터레이터를 순차 탐색 할때 itr < endItr보다는 itr != endItr을 사용하라.
swap()을 이용하여 vector가 할당한 메모리 영역을 해제할 수 있다. vector<bool>은 사용하지 마라.
모던 C++ (C++17~) polymorphic_allocator가 추가되어 할당시 런타임 다형성을 지원합니다. 메모리 리소스를 사용하여 메모리 풀을 손쉽게 만들 수 있습니다.
컨테이너에 알고리즘의 멤버 버전이 있다면, 멤버 버전이 효율이 더 좋다.
모던 C++ (C++11~) 람다 표현식이 추가되어 1회용 익명 함수를 만들 수 있습니다. (C++11~) function이 추가되어 ()로 호출 가능한 함수자를 저장할 수 있습니다. (C++11~) mem_fn()이 추가되었습니다. 인자가 있는 멤...
string과 wstring은 public Non-Virtual 소멸자이므로 상속하여 재구현 하지 마라. 수정될 필요가 없는 문자열 데이터는 const char* 나 const wchar_t*로 관리하라.(배열이나 string, wstring을 쓰면 복제된다....
auto_ptr은 deprecate 되었으니 더이상 사용하지 마라. 복사 부하, 상수성, 스마트 포인터를 이용하여 좀더 단단한 코딩 계약을 만들어라.
모던 C++ (C++11~) constexpr이 추가되어 컴파일 타임 프로그래밍이 강화됐습니다. (C++11~) static_assert()가 추가되어 컴파일 타임 진단이 가능해 졌습니다. (C++11~) noexcept 연산자가 추가되어 해당 함수...
브라우저 개발자 도구 이용하기
JavaScript Debugger (Nightly) 를 이용하면 VSCode 에서 직접 디버깅을 할 수 있습니다.
모듈(ECMAScript6)
코딩 패턴 - 즉시 실행 함수를 이용한 모듈화
자바스크립트에서 상속이 필요한가?
예외 탐지(try-catch())
Promise
function 오른쪽에 *을 붙이면 호출시마다 일시 정지하고 재개하는 generator함수를 만들 수 있습니다. C++ 코루틴과 유사합니다.
strict mode
기본 생성자가 필요하다면 명시적으로 구현하고, 필요없다면 못쓰게 만들어라. 값 생성자에서는 필요한 인자를 모두 나열하고 초기화하라. 인자가 1개인 값 생성자(형변환 생성자)는 explicit로 암시적 형변환을 차단하라. 암시적 복사 생성자가 정상...
멤버 변수가 1개라면, 암시적 복사 대입 연산자가 정상 동작하도록 멤버 변수 정의시 스마트 포인터(shared_ptr 등)를 사용하고, 필요없다면 못쓰게 만들어라. 멤버 변수가 2개 이상이라면, 복사 대입 연산자를 예외에 안전하도록 swap()으로 구현하고, ...
획득된 자원은 꼭 소멸시켜라. 암시적 소멸자가 정상 작동하도록 멤버 변수 정의시 스마트 포인터(auto_ptr, unique_ptr, shared_ptr 등)를 사용하라. 다형 소멸이 필요하면 부모 개체에 가상 소멸자를 사용하라.(가상 소멸자가 아니면 ...
은근슬쩍 만들어 지는 것들은 유효한지 검토하고, 유효하지 않다면 사용하지 못하게 막아라.
개체는 new-delete 쌍으로 생성/소멸 하라. 배열은 new[]-delete[] 쌍으로 생성/소멸하라. new[]한 것을 delete 만 하면, 메모리 릭이 발생한다. 꼭 delete[]하라. delete는 널 값이면 아무 작업 안한다. 괜히 널검...
멤버 변수 초기화시, 생성후 대입하지 말고 초기화 리스트를 사용하라.(초기화 리스트의 순서는 멤버 변수 선언 순서에 맞춰라.) 생성자에서 필요한 인자를 모두 나열하고 초기화하라. 메모리 패딩을 고려하여 멤버 변수 선언 순서를 정하라. 암시적 복사...
PImpl 이디엄은 멤버 변수 접근 부하, 메모리 공간 부하, 과도한 힙 사용의 부하가 있으니, 상황에 맞게 도입하라.
멤버 변수를 수정하지 않는다면, 상수 멤버 함수로 작성하라. 정적 멤버 함수는 obj.f() 가 아닌 T::f() 와 같이 호출하라. 자식 개체에서 부모 개체의 비 가상 함수를 재정의 하지 마라. 가상 함수를 정의하면 가상 함수 테이블을 위한 추...
부모 개체의 멤버 함수를 오버로딩 하지 마라. 오버로딩 함수 탐색 규칙에서 제외된다. 자식 개체를 부모 개체에 대입하지 마라. 아무런 오류 없이 복사 손실 된다. 구현 코드가 없는 단위 전략 인터페이스인 경우에만 다중 상속하라. 소멸자에서 가이드...
기능 스펙을 정의하여 코딩 계약을 맺으려면 인터페이스로 정의하라. 기능 스펙과 어느 정도의 공통 기능을 제공하려면 추상 클래스로 정의하라.
잘못 사용하기엔 어렵게, 바르게 사용하기엔 쉽게 구현하라. 단일 책임 원칙(Single Responsibility Principle)을 준수하여 사용하기 쉽게 만들어라. 암시적 정의를 차단하여 의도한 동...
유틸리티 클래스
우리 팀은 프로젝트 하나가 백만라인이야~ 대단하지?
소스코드에도 유통기한이 있다면 그 기간을 만년으로 하고 싶다.
프로그래밍시 작명의 기술은 너무나도 중요합니다. 가독성 향상을 통해 생산성을 극대화해주고, 동료를 배려하는 아트 코딩의 시작점입니다. 좋은 이름을 짓는다면, 코드를 읽은 동료들이 당신의 고민과 배려에 감사해 할거에요.
단위 테스트란 하나의 기능 단위를 테스트하는 것을 말합니다. 혹은 단위 기능들을 복합하여 다시 하나의 단위 테스트를 만들 수도 있습니다.
이럴수가… 한 동료가 기능을 만들어서 테스터에게 보냈는데 버그가 하루만에 10개 넘게 왔군요? 동료가 열심히 고쳐서 다시 테스터에게 보냈더니 이번엔 또다른 것 10개가 돌아왔네요. 또 동료가 열심히 고쳐서 다시 테스터에게 보냈더니 이번엔 예전에 고친 버그가 재현되네요.(테스트 자동...
이거 얼마나 걸릴까? (약 10초뒤) 3주요.
우리는 보통 “무엇을 개발하라” 라는 요구사항이 떨어지면, 어떤것 부터 하게 되나요?
보통은 구현을 할때 정상적인 시나리오로 동작할 수 있도록 코드를 구현하고, 그뒤 테스트를 하곤 합니다.
완전한 하루
애자일 절권도
개요 마크다운은 간결한 문법으로 HTML 작성을 보조하는 도구입니다.
개요 VSCode 는 에디터이기 때문에, C++ 을 이용한 개발을 하려면 MinGW-w64(Minimalist GNU for Windows)와 VSCode Extension의 C/C++ Extension Pack 설치가 필요합니다.
개요 Git은 소스코드의 이력을 관리하는 편리한 도구 입니다.
개요 Git 을 설치했다면 VSCode에서 Panel(TERMINAL)과 UI를 통해 Git을 사용할 수 있습니다.
개요 Github는 Git으로 소스코드를 관리하는 원격 저장소 서비스 입니다. Git이 설치되어 있어야 하며, Github에 회원가입을 해야 사용할 수 있습니다.
개요 C++ 에서는 프로젝트를 구성하는 파일이 여러개 라면 Make 환경을 구축해야 해야 합니다. Makefile을 직접 작성하는 방법도 있지만, 손쉬운 유지관리를 위해 CMake를 사용하는 방법이 좋습니다. CMake를 사용하려면, CMake 설치와 VSCode Extension...
개요 Windows용 VSCode의 기본 터미널은 PowerShell 입니다. 기호에 따라 다른 터미널로 변경할 수 있습니다.
개요 단위 테스트는 코드의 신뢰를 높여 사이드 이펙트를 최소화 해주고, 코드의 인터페이스도 깔끔하게 해주는 스킬입니다. 코드 작성시 기능 구현만 완료하면 반쪽 짜리입니다. 꼭 단위 테스트를 만들어 완성도를 올리시기 바랍니다.
개요 GoogleTest는 매크로를 통해 테스트 함수를 작성하고, 매크로 함수들을 통해 테스트를 수행합니다.
일단 기능구현을 하고 나중에 주석을 적을께요.
전 주석이 많으면 코드가 오히려 눈에 안들어와요.
주석도 리팩토링의 대상일까요?
함수의 주석을 작성하고자 할때 여러분은 어디에 작성을 하시나요?
맞는 말입니다.
C++ 에서 문법적으로는 다음의 두가지 주석이 있습니다. ```cpp //
예외 안전(safe) 코드는 예외가 발생하지 않는 코드가 아니라, 예외가 발생해도 안전하게 복원되고 계속 동작해도 무방하게 예외 보증하는 코드다. 예외 상황을 사전에 예측하고 프로그래밍 하라. 모든 함수는 실패할 수 있다고 가정하고 프로그래밍 해라. ...
해결할 수 없는 예외 상황은 오류 코드 리턴보다는 강제성이 있는 throw로 보고하라. 예외를 해결할 수 있는 곳에서 탐지하라. catch()에서 예외 개체가 복사 생성되지 않도록 참조자로 받아라. 예외를 그대로 전파할 경우에는 throw;를 사...
모던 C++ (C++11~) 동적 예외 사양은 deprecate 되었습니다. 예외를 나열하는 것보다 noexcept로 예외를 방출하느냐 안하느냐만 관심을 둡니다. (C++17~) 동적 예외 사양 관련해서 throw()가 deprecate 되었습니다. 이제 ...
사전 가정과 사후 가정을 진단하라. 진단 코드가 최소화 되도록, 포인터 보다는 참조자를 사용하고, 코딩 계약을 단단하게 만들어라.
예외에 안전하도록 기본 보증과 강한 보증을 하라. 기본 보증이 되도록 스마트 포인터나 Holder를 사용하라. 강한 보증이 되도록 클래스를 설계하라.(예외 안전에 좋은 클래스 설계 참고) 모듈의 경계에서 예외가 방출되지 않도록 예외를 catch(...
윈도우즈는 메시지 기반으로 프로그래밍을 하며, 다음의 메시지들이 예약된다.
메시지 처리를 위한 전형적인 메시지 루프는 다음과 같다.
일반적인 메시지 루프는 다음과 같다. 1 2 3 4 5 MSG msg; while (::GetMessage(&msg, NULL, NULL, NULL)) { ::TranslateMessage(&msg); ::DispatchMessage(&msg); }
Modeless 대화상자를 지원하기 위해서는 대화상자에서 직접 처리하는 키보드 메시지(TAB, ESC, ENTER, ALT+니모닉 등)를 중복해서 처리하지 않도록 다음과 같이 메시지 루프를 사용해야 한다.