CppKorea/CppCoreGuidelines

한글화 프로젝트 진행상황 공유

luncliff opened this issue · 2 comments

한글화 프로젝트 진행상황을 공유할 수 있도록 Issue를 개설합니다.

체크박스의 마킹을 통해 번역이 진행된 부분/필요한 부분을 확인하실 수 있습니다.
마킹된 항목들은 한글화가 진행된 부분을 의미하며, 나머지는 한글화가 필요한 항목들입니다.

현재는 전부 원문을 표기하고 있습니다만, 점진적으로 한글화가 진행된 부분은 한글 제목으로 교체하겠습니다.

Guidelines

이하의 진행상황은 master 브런치를 대상으로 합니다.

  • ReadMe
  • Abstract
  • Reference

Introduction

  • In.target: Target readership
  • In.aims: Aims
  • In.not: Non-aims
  • In.force: Enforcement
  • In.struct: The structure of this document
  • In.sec: Major sections

Philosophy

  • P.1: 아이디어를 직접 코드로 표현하라
  • P.2: ISO 표준 C++로 작성하라
  • P.3: 의도를 표현하라
  • P.4: 이상적으로 프로그램은 정적으로 타입 안전해야 한다
  • P.5: 런타임 검사보다는 컴파일 타임 검사를 선호하라
  • P.6: 컴파일 타임에 검사할 수 없다면 런타임에 검사할 수 있어야 한다
  • P.7: 런타임 오류는 초기에 잡아라
  • P.8: 리소스가 새도록 하지 마라
  • P.9: 시간이나 공간을 낭비하지 마라
  • P.10: 변경 가능한 데이터보다 불변의 데이터를 선호하라
  • P.11: 지저분한 구조가 코드를 통해 퍼지기 보단, 캠슐화를 하라
  • P.12: 필요에 맞게 지원 도구를 사용하라
  • P.13: Use support libraries as appropriate

Performance

Naming and Layout Rules

Guidelines Support Library

Source Files

  • SF.1: 다른 관례를 따르는 중이 아니라면 .cpp는 코드 파일에, .h는 인터페이스 파일에 사용하라
  • SF.2: .h 파일에는 개체 변수(object definition) 혹은 inline이 아닌 함수의 정의가 있어서는 안된다
  • SF.3: .h 파일은 여러 소스 파일에서 사용되는 선언을 담아라
  • SF.4: 파일에서 무언가 선언하기 전에 .h를 include하라
  • SF.5: .cpp파일은 반드시 해당 인터페이스를 정의하는 .h를 include해야 한다
  • SF.6: using namespace는 네임스페이스의 이름 바꾸기, std처럼 기본적인 라이브러리, 혹은 지역 유효범위 안에서(만) 사용하라
  • SF.7: 헤더파일에서는 전체 유효범위(global scope)에 주는 using namespace를 작성하지 마라
  • SF.8: 모든 .h파일에서 #include 가드(guard)를 사용하라
  • SF.9: 소스 파일들이 순환 의존(cyclic dependencies)하게 하지마라
  • SF.10: 묵시적으로 #include된 이름이 필요하지 않도록 하라
  • SF.11: 헤더 파일은 독립적으로 사용할 수 있게(self-contained) 만들어라
  • SF.20: namespace는 논리적 구조를 표현할 때 사용하라
  • SF.21: 헤더에서 이름없는(anonymous) 네임스페이스를 사용하지 마라
  • SF.22: 이름없는(anonymous) 네임스페이스는 내부(internal)/노출시키지 않는(non-exported) 개체에 사용하라

The Standard Library

  • SL.1: 가능한 곳 어디에서든 라이브러리를 사용하라
  • SL.2: 다른 라이브러리보다는 표준 라이브러리를 우선적으로 사용하라
  • SL.3: 비표준 개체를 네임스페이스 std에 추가하지 말라
  • SL.4: 타입 안전성을 지키면서 표준 라이브러리를 사용하라

Containers

  • SL.con.1: C 배열을 사용하기보다 STL의 arrayvector를 사용하라
  • SL.con.2: 다른 컨테이너를 사용할 이유가 있지 않다면 STL vector를 기본으로 사용하라
  • SL.con.3: 경계조건에서 발생하는 에러를 피하라

String

  • SL.str.1: 문자열을 제대로 소유하기 위해서는 std::string을 사용하라
  • SL.str.2: 문자들의 나열을 참조하기 위해서는 std::string_viewgsl::string_span을 사용하라
  • SL.str.3: 0으로 끝나는 문자들의 나열인 C 스타일의 문자열을 표현하려면 zstringczstring을 사용하라
  • SL.str.4: 하나의 단일 문자에 대한 참조를 의도할 때 char*를 사용하라
  • SL.str.5: 문자열을 표현할 필요없이 바이트 값을 참조하려면 std::byte를 사용하라
  • SL.str.10: 지역 언어에 민감한 문자열에 대한 처리가 필요할 때에는 std::string을 사용하라
  • SL.str.11: 문자열을 수정할 필요가 있을때는 std::string_view보다는 gsl::string_span을 사용하라
  • SL.str.12: 표준 라이브러리 std::string을 의도할 때는 s 접미사를 사용하라

I/O Stream

  • SL.io.1: 단일 문자 단위의 입력은 꼭 필요할때에만 사용하라
  • SL.io.2: 항상 읽을때에는 형식화되지 않은 입력을 고려하라
  • SL.io.3: 입출력을 위해서는 iostream을 선호하라
  • SL.io.10: printf계열의 함수를 사용하지 않는다면 ios_base::sync_with_stdio(false)를 호출하라
  • SL.io.50: endl의 사용을 피하라

Regex

Time

The C Standard Library

  • S.C.1: setjmp/longjmp를 사용하지 말라

Templates and Generic Programming

템플릿 사용 규칙 요약:

  • T.1: 코드의 추상화 수준을 높이기 위해 템플릿을 사용하라
  • T.2: 여러가지 실행인자 타입들에 적용되는 알고리즘을 표현할 때 템플릿을 사용하라
  • T.3: 컨테이너와 구간(range)을 표현할때 템플릿을 사용하라
  • T.4: 문법 트리 조작을 표현하기 위해 템플릿을 사용하라
  • T.5: 제네릭 프로그래밍과 개체지향 기술을 결합해 비용이 아닌 강점을 증폭시켜라

컨셉 사용 규칙

  • T.10: 모든 템플릿 인자에 컨셉을 명시하라
  • T.11: 가능한 모든 경우 표준 컨셉을 사용하라
  • T.12: 지역 변수에 auto 보다는 컨셉의 이름을 사용하라
  • T.13: 단순하거나 단일 타입을 인자로 받는 컨셉에는 약식 표기를 사용하라

컨셉 정의 규칙

  • T.20: 유의미한 의미구조가 없는 "컨셉"을 피하라
  • T.21: 컨셉에서는 연산들의 완전한 집합(complete set)을 요구하라
  • T.22: 컨셉에서 쓸 수 있도록 공리를 명시하라
  • T.23: 정제된 컨셉(refined concept)은 더 범용적인 경우에 새로운 패턴을 더해서 차별화하라
  • T.24: 의미구조만 다른 컨셉은 Tag 클래스 혹은 Traits를 사용해 차별화하라
  • T.25: 제약이 서로 대비되지 않게 하라
  • T.26: 단순한 문법보다는 사용 패턴을 고려해서 컨셉을 정의하라

템플릿 인터페이스 규칙

  • T.40: 알고리즘에 연산(operation)을 전달할때는 함수 개체를 사용하라
  • T.41: 템플릿의 컨셉에서는 오직 필요한 특성(property)만 요구하라
  • T.42: 템플릿 별칭을 구현사항을 숨기거나 표기를 간단히 할 때 사용하라
  • T.43: 타입에 별명을 붙일때 typedef 보다는 using을 사용하라
  • T.44: (할 수 있다면) 함수 템플릿은 클래스 템플릿의 인자 타입을 유도(deduce)할 때 사용하라
  • T.46: 템플릿 인자들은 최소한 Regular혹은 SemiRegular하도록 하라
  • T.47: 일반적인 이름을 가지고 있으면서 쉽게 찾을 수 있고 제약이 거의 없는 템플릿은 지양하라
  • T.48: 컴파일러가 컨셉을 지원하지 않는다면 enable_if로 유사하게 작성하라
  • T.49: 가능하다면 타입 제거는 피하라

템플릿 정의 규칙

  • T.60: 문맥에 따라 달라질 수 있는 템플릿은 최소화 하라
  • T.61: 너무 많은 멤버를 매개변수화 하지 말라 (SCARY)
  • T.62: 종속적이지 않은 클래스 템플릿 멤버들은 템플릿이 아닌 상위 클래스에 배치하라
  • T.64: 클래스 템플릿의 대안적(alternative) 구현을 제공할 때는 특수화를 사용하라
  • T.65: 함수의 대안적(alternative) 구현을 제공할 때는 Tag dispatch를 사용하라
  • T.67: 정규적이지 않은 타입(irregular types)들의 대안적 구현을 제공할 때는 특수화를 사용하라
  • T.68: 모호하지 않도록 템플릿에서는 () 보다는 {}를 사용하라
  • T.69: 제약없는(unqualified) 비-멤버 함수 호출은 해당 부분이 변경될 수 있도록 하려는게 아니라면 템플릿 내에서 사용하지 말아라

템플릿과 상속구조 규칙

  • T.80: 충분한 고려 없이 클래스 계층구조를 템플릿으로 바꾸지 말아라
  • T.81: 계층구조와 배열을 섞어서 사용하지 말아라
  • T.82: 가상 함수를 원하지 않는다면 계층 구조를 제거하라(linearize)
  • T.83: 멤버 함수는 템플릿이면서 virtual한 함수로 선언해선 안된다
  • T.84: 안정된 ABI를 지원하고자 할때는 핵심 구현에 템플릿을 쓰지 마라

가변인자 템플릿규칙

  • T.100: 다양한 타입을 가지고 가변적인 수의 실행인자들을 처리하는 함수가 필요할 때는 가변 템플릿을 사용하라
  • T.101: ??? How to pass arguments to a variadic template ???
  • T.102: ??? How to process arguments to a variadic template ???
  • T.103: 동일 타입의 실행인자들을 위해서 가변템플릿을 사용하지 마라

메타프로그래밍 규칙

  • T.120: 정말 필요한 경우에만 템플릿 메타프로그래밍을 사용하라
  • T.121: 컨셉을 모방(emulate)하기 위해 템플릿 메타프로그래밍을 사용하라
  • T.122: 템플릿(대부분 템플릿 별칭)은 컴파일 시간에 타입을 계산할때 사용하라
  • T.123: 컴파일 시간에 값을 계산한다면 constexpr 함수를 사용하라
  • T.124: 가능한 표준 라이브러리의 TMP 기능들을 사용하라
  • T.125: 만약 표준 라이브러리의 TMP 기능으로 충분하지 않다면, 가능한 이미 존재하는 라이브러리를 사용하라

다른 템플릿 규칙

  • T.140: 재사용 가능성이 있는 모든 연산은 이름을 붙여라
  • T.141: 단순한 함수 개체가 한곳에서만 필요하다면 이름없는 람다를 사용하라
  • T.142: 템플릿 변수로 표기를 간단히 하라
  • T.143: 범용적이지 않은 코드는 계획없이 작성하지 말아라
  • T.144: 함수 템플릿은 특수화하지 말라
  • T.150: 해당 클래스가 개념에 부합하는지를 static_assert를 사용해 확인하라

Resource management

  • R.1: 자원 핸들과 RAII(자원 획득시 초기화)를 사용해서 자동적으로 관리되도록 하라
  • R.2: 인터페이스에서는, 포인터는 서로 다른 개체들을 표시하기 위해서만 사용하라
  • R.3: 원시 포인터(T*)는 소유를 의미하지 않는다
  • R.4: 참조(T&)는 소유를 의미하지 않는다
  • R.5: 유효 범위 안의 개체를 선호하라. 불필요한 동적할당을 하지 마라
  • R.6: const가 아닌 전역 변수를 지양하라

할당과 해제

  • R.10: malloc()free()의 사용을 피하라
  • R.11: 명시적인 newdelete 호출을 지양하라
  • R.12: 명시적인 할당의 결과는 즉시 관리 개체에 전달하라
  • R.13: 하나의 표현식 구문에서 명시적 자원 할당은 최대 한번만 수행하라
  • R.14: ??? 배열 vs. 포인터 매개변수
  • R.15: 할당/해제가 짝을 이루도록 중복정의하라

스마트 포인터

  • R.20: 소유권을 나타내기 위해 unique_ptr 혹은 shared_ptr를 사용하라
  • R.21: 소유권을 공유할 필요가 없다면 shared_ptr보다는 unique_ptr를 선호하라
  • R.22: shared_ptr를 만들때는 make_shared()를 사용하라
  • R.23: unique_ptr를 만들때는 make_unique()를 사용하라
  • R.24: shared_ptr의 순환참조를 부수기 위해 weak_ptr를 사용하라
  • R.30: 수명주기 의미구조를 표현하기 위해서만 스마트 포인터를 매개변수로 사용하라
  • R.31: 표준 스마트 포인터를 사용하지 않고 있다면, 표준에서 사용하는 기본 패턴을 사용하라
  • R.32: 함수가 widget의 소유권을 맡는다는 것을 표현하기 위해 unique_ptr<widget>를 매개변수로 사용하라
  • R.33: 함수가 widget을 새로 설정한다는 것을 표현하기 위해 unique_ptr<widget>&를 사용하라
  • R.34: 함수가 소유자 중 하나라는 것을 표현하기 위해 shared_ptr<widget>를 매개변수로 사용하라
  • R.35: 함수가 공유 포인터를 재설정한다는 것을 표현하기 위해 shared_ptr<widget>&를 매개변수로 사용하라
  • R.36: 함수가 개체에 대한 참조 카운트를 유지한다는 것을 표현하기 위해 const shared_ptr<widget>&을 매개변수로 사용하라 ???
  • R.37: 재명명(aliased)된 스마트 포인터에서 획득한 포인터 혹은 참조를 전달하지 마라

Profiles

  • Pro.type: 타입 안전성
  • Pro.bounds: 경계 안전성
  • Pro.lifetime: 수명 안전성

규칙이 아닌 것들과 근거없는 이야기들

  • NR.1: 금지: 모든 선언이 함수의 상단에 오게 하라
  • NR.2: 금지: 함수에서 오직 하나의 return 구문을 사용하라
  • NR.3: 금지: 예외를 사용하지 마라
  • NR.4: 금지: 클래스 선언을 각각의 파일에 배치하라
  • NR.5: 금지: 생성자에서 많은 일을 하지마라; 대신 2 단계 초기화를 사용하라
  • NR.6: 금지: 모든 정리 동작을 함수 끝에 배치하고 goto exit을 사용하라
  • NR.7: 금지: 모든 데이터 멤버를 protected로 하라

Interfaces

인터페이스 규칙

  • I.1: 인터페이스는 명확하게(explicit) 작성하라
  • I.2: const가 아닌 전역변수를 지양하라
  • I.3: 싱글톤 패턴을 지양하라
  • I.4: 인터페이스가 타입 시스템을 정확하고 엄격하게 준수하도록 만들어라
  • I.5: (하나라도 있다면) 사전 조건을 기술하라
  • I.6: 사전 조건을 표현하고 싶다면 Expects()를 사용하라
  • I.7: 사후 조건을 기술하라
  • I.8: 사후 조건을 표현하고 싶다면 Ensures()를 사용하라
  • I.9: 인터페이스가 템플릿이라면 컨셉(Concept)을 사용해서 매개 변수를 문서화하라
  • I.10: 요구된 작업의 수행 실패를 알리기 위해 예외를 사용하라
  • I.11: 원시 포인터(T*) 혹은 참조(T&)를 사용해 소유권을 전달하지 마라
  • I.12: null이 되어선 안되는 포인터는 not_null로 선언하라
  • I.13: 배열을 단일 포인터로 전달하지 마라
  • I.22: 전역 개체가 복잡하게 초기화되지 않도록 하라
  • I.23: 함수 인자 개수를 최소로 유지하라
  • I.24: 같은 타입의 관련없는 매개 변수가 붙어있지 않도록 하라
  • I.25: 클래스 계층에 대한 인터페이스로 추상 클래스를 사용하라
  • I.26: 크로스 컴파일러 ABI를 원한다면 C 스타일 코드를 사용하라
  • I.27: 변화가 적은(stable) ABI를 원한다면, Pimpl idiom 사용을 고려하라
  • I.30: 규칙을 위반하는 코드는 캡슐화하라

Functions

함수 정의

  • F.1: 의미있는 동작들을 "묶어서" 함수로 만들고 신중하게 이름을 지어라
  • F.2: 함수는 하나의 논리적 동작만 수행해야 한다
  • F.3: 함수는 간결하고 단순하게 유지하라
  • F.4: 함수가 컴파일 시간에 평가되어야 한다면 constexpr로 선언하라
  • F.5: 함수가 매우 짧고 수행시간이 중요하다면 inline으로 선언하라
  • F.6: 함수가 예외를 던지지 않는다면 noexcept로 선언하라
  • F.7: 보편성을 고려한다면, 스마트 포인터 대신에 T*T& 타입의 인자를 사용하라
  • F.8: 순수 함수를 선호하라
  • F.9: 사용되지 않는 인자는 이름이 없어야 한다

매개변수 전달 표현(parameter passing expression)

  • F.15: 정보를 전달 할 때 단순하고 관습적인 방법을 선호하라
  • F.16: "입력(in)" 매개변수는 복사 비용이 적게 드는 타입의 경우 값으로 전달하고, 그 외에는 상수 참조형으로 전달하라
  • F.17: "입출력(in-out)" 매개변수는 비상수 참조형으로 전달하라
  • F.18: "넘겨주는(will-move-from)" 매개변수는 X&&타입과 std::move로 전달하라
  • F.19: "전달(forward)" 매개변수는 TP&&타입과 std::forward로만 전달하라
  • F.20: "출력(out)"에는 매개변수보다는 값을 반환하는 방법을 선호하라
  • F.21: "출력"값 여러 개를 반환할 때는 튜플이나 구조체를 선호하라

매개변수 전달 의미구조(parameter passing semantic)

  • F.22: T* 혹은 owner<T*>를 단일 개체를 지정하기 위해 사용하라
  • F.23: "null"이 허용되지 않는다면 not_null<T>를 사용해 표시하라
  • F.24: 범위를 지정할 때는 span<T>혹은 span_p<T>를 사용하라
  • F.25: C 스타일 문자열에는 zstring 혹은 not_null<zstring>을 사용하라
  • F.26: 포인터가 필요한 곳에 소유권을 전달할 때는 unique_ptr<T>를 사용하라
  • F.27: 소유권을 공유할 때는 shared_ptr<T>를 사용하라
  • F.60: "인자가 없을 경우"를 허용한다면 T&보다는 T*를 선호하라

값 반환 의미구조

  • F.42: 위치를 나타내는 경우에만 T*를 반환하라
  • F.43: 절대로 (직접적이든 간접적이든) 지역 개체의 포인터나 참조를 반환하지 말아라
  • F.44: 복사를 권장하지 않거나 "개체를 항상 반환"한다면 T&를 반환하라
  • F.45: T&&를 반환하지 말아라
  • F.46: main()int를 반환해야 한다
  • F.47: 대입 연산자는 T&를 반환하라
  • F.48: return std::move(local)은 사용하지 말아라

기타 함수 규칙

  • F.50: 함수를 쓸 수 없을 때는 람다를 사용하라(지역 변수를 캡쳐하거나 지역 함수를 작성할 때)
  • F.51: 선택할 수 있다면, 중복 정의보다는 기본 전달인자를 선호하라
  • F.52: 지역적으로 사용된다면 람다의 참조 캡쳐를 선호하라
  • F.53: 지역적으로 사용되지 않는다면 참조 캡쳐를 피하라
  • F.54: this를 캡쳐할 때는, 모든 변수를 명시적으로 캡쳐하라(기본 캡쳐를 사용하지 않는다)
  • F.55: va_arg 전달인자를 사용하지 말아라

Expressions and statements

  • ES.1: 다른 라이브러리나 "직접 짠 코드" 대신 표준 라이브러리를 사용하라
  • ES.2: 언어 기능을 바로 사용하기는 보다 적절히 추상화하라

선언

  • ES.5: 유효범위(scope)는 작게 유지하라
  • ES.6: for 문의 변수는 유효범위를 제한하기 위해 초기화와 조건 검사부분에서만 선언하라
  • ES.7: 일반적이거나 지역범위 변수들의 이름은 짧게, 그렇지 않다면 길게 하라
  • ES.8: 비슷해보이는 이름은 피하라
  • ES.9: ALL_CAPS 같은 이름을 피하라
  • ES.10: 선언은 (오직) 하나의 이름을 선언해야 한다
  • ES.11: 타입 이름의 불필요한 반복을 막을때는 auto를 사용하라
  • ES.12: 이름을 덮어쓰지 않도록 하라
  • ES.20: 항상 개체를 초기화하라
  • ES.21: 사용할 필요가 없을 때 변수나 상수를 선언하지 마라
  • ES.22: 변수를 초기화할 값이 생길 때까지 선언하지 마라
  • ES.23: {} 초기화 문법을 사용하라
  • ES.24: 포인터는 unique_ptr<T>에 담아라
  • ES.25: 값을 변경하지 않는다면 개체를 const 혹은 constexpr로 선언하라
  • ES.26: 서로 상관없는 목적에 하나의 변수를 사용하지 마라
  • ES.27: 스택에서 사용되는 배열은 std::arraystack_array를 사용하라
  • ES.28: 복잡한 초기화, 특히 const 변수의 초기화에는 람다를 사용하라
  • ES.30: 프로그램 텍스트를 다루기(manipulate) 위해 매크로를 사용하지 마라
  • ES.31: 매크로를 상수나 "함수"에 사용하지 마라
  • ES.32: 모든 매크로는 ALL_CAPS 형태로 선언하라
  • ES.33: 매크로를 사용해야만 한다면, 고유한 이름을 사용하라
  • ES.34: (C-스타일의) 가변인자 함수를 정의하지 마라

표현식

  • ES.40: 복잡한 표현식을 피하라
  • ES.41: 연산자 우선순위가 불분명하면, 소괄호를 사용하라(parenthesize)
  • ES.42: 포인터는 간단하고 직관적인 형태로 사용하라
  • ES.43: 평가 순서가 정의되지 않은 표현식은 사용하지 마라
  • ES.44: 함수 인자가 표현식 평가 순서의 영향을 받지 않게 하라
  • ES.45: 이유를 알 수 없는 상수(magic constant)를 사용하지 마라; 상징적인 상수를 사용하라
  • ES.46: 타입 범위를 축소하는 변환을 피하라
  • ES.47: 0 혹은 NULL보다는 nullptr를 사용하라
  • ES.48: 타입 변환(cast)을 피하라
  • ES.49: 타입 변환을 사용해야만 한다면, 미리 정의된 방법으로 변환(named cast)하라
  • ES.50: const를 제거하지 마라
  • ES.55: 범위 검사가 필요없게 하라
  • ES.56: std::move()는 개체를 다른 유효범위로 명시적으로 옮겨야 할때만 사용하라
  • ES.60: 자원을 관리하는 함수 외부에서 newdelete 사용을 피하라
  • ES.61: 배열은 delete[], 단일 개체는 delete를 사용해서 해제하라
  • ES.62: 서로 다른 배열에 대한 포인터를 비교하지 마라
  • ES.63: 복사 손실(slice)이 없도록 하라
  • ES.64: 개체를 생성할 때는 T{e}표기를 사용하라
  • ES.65: 유효하지 않은(invalid) 포인터를 역참조하지 마라

구문

  • ES.70: 선택을 하는 경우에는 if구문보다는 switch구문을 사용하라
  • ES.71: 가능하다면 일반 for구문 보다 범위기반 for-구문을 사용하라
  • ES.72: 루프 변수가 있다면 while-구문보다 for-구문을 사용하라
  • ES.73: 루프 변수가 없다면 for-구문보다 while-구문을 사용하라
  • ES.74: 루프 변수는 for-구문의 초기화 부분에서 선언하라
  • ES.75: do-구문을 사용하지 마라
  • ES.76: goto를 사용하지 마라
  • ES.77: breakcontinue의 사용을 최소화하라
  • ES.78: 내용이 있는 casebreak하라
  • ES.79: (오직) 일반적인 경우를 처리하기 위해서 default를 사용하라
  • ES.84: 이름이 없는 지역변수는 선언(하려고)하지 마라
  • ES.85: 비어있는 구문은 눈에띄게 하라
  • ES.86: for 반복문(body) 안에서 루프 변수를 변경하지 마라
  • ES.87: 조건에 불필요한 ==!=를 사용하지 마라

산술연산

  • ES.100: 부호가 있는 타입과 없는 타입을 함께 연산하지 마라
  • ES.101: 비트 조작시에는 부호가 없는(unsigned) 타입을 사용하라
  • ES.102: 연산에는 부호가 있는(signed) 타입을 사용하라
  • ES.103: Overflow가 발생하지 않게 하라
  • ES.104: Underflow가 발생하지 않게 하라
  • ES.105: 0으로 나누지 않도록 하라
  • ES.106: 음수값을 막으려고 unsigned를 사용하지 마라
  • ES.107: 배열 접근에는 unsigned를 쓰지 말고 gsl::index를 사용하라

Error handling

  • E.1: 설계 과정 초기에 오류 처리에 대한 전략을 수립하라
  • E.2: 함수가 맡은 작업을 처리할 수 없다는 것을 알리기 위해 예외를 발생시켜라
  • E.3: 예외는 오류 처리에만 사용하라
  • E.4: 불변조건을 중심으로 오류 처리 전략을 설계하라
  • E.5: 생성자에서 불변조건을 설정하도록 하고, 그렇게 할 수 없으면 예외를 발생시켜라
  • E.6: RAII를 사용하여 누수를 방지하라
  • E.7: 선행조건을 기술하라
  • E.8: 후행조건을 기술하라
  • E.12: throw를 허용하지 않거나 불가능한 함수에는 noexcept를 사용하라
  • E.13: 객체를 직접적으로 소유하는 중에는 예외를 발생시켜선 안된다
  • E.14: 목적에 맞게 설계된 사용자 정의 타입을 예외로 사용하라 (내장 타입은 안된다)
  • E.15: 계층 구조가 있는 예외는 참조를 사용해서 잡아라
  • E.16: 소멸자, 자원해제, swap은 절대 실패해선 안된다
  • E.17: 각각의 함수들에서 모든 예외를 처리하려고 하지 마라
  • E.18: 명시적인 try/catch문의 사용을 최소화하라
  • E.19: 적당한 리소스 핸들을 사용할 수 없다면 해제방법을 나타낼 final_action 객체를 사용하라
  • E.25: 예외를 던질 수 없다면, 자원관리를 위해 RAII를 시뮬레이션 하라
  • E.26: 예외를 던질 수 없다면, 빠른 실패 전략을 고려하라
  • E.27: 예외를 던질 수 없다면, 체계적으로 에러 코드를 사용하라
  • E.28: 전역 상태에 기반한 에러 처리를 지양하라(errno처럼)
  • E.30: 예외 명세를 사용하지 마라
  • E.31: 적합한 순서로 catch를 배치하라

Enumerations

  • Enum.1: 매크로보다 열거형을 사용하라
  • Enum.2: 서로 관련있는 상수들의 집합을 표현하기 위해 열거형을 사용하라
  • Enum.3: 단순한 enum보다 enum class를 선호하라
  • Enum.4: 안전하고 단순한 사용을 위해 열거형들을 위한 연산을 정의하라
  • Enum.5: 열거체들을 ALL_CAPS형태로 사용하지 마라
  • Enum.6: 이름없는 열거형을 지양하라
  • Enum.7: 필요할 때만 기본 타입을 명시하라
  • Enum.8: 열거체들의 값은 필요할때만 명시하라

C-Style Programming

  • CPL.1: C보다 C++를 사용하라
  • CPL.2: 반드시 C를 써야한다면, C와 C++의 공통집합을 쓰고, C++로 코드를 컴파일하라
  • CPL.3: C 인터페이스를 써야한다면, 호출되는 코드 안에서는 C++를 사용하라

Constants and Immutability

  • Con.1: 기본적으로 객체를 변경 불가능하도록 만들어라
  • Con.2: 기본적으로 멤버 함수들은 const로 만들어라
  • Con.3: 기본적으로 포인터와 참조는 const로 전달하라
  • Con.4: 개체 생성 이후 변하지 않는 값은 const로 정의하라
  • Con.5: 컴파일 시간에 계산될 수 있는 값은 constexpr을 사용하라

Concurrency and Parallelism

  • CP.1: 코드가 멀티스레드 프로그램의 일부로 동작할 것이라 가정하라
  • CP.2: 데이터 경쟁을 피하라
  • CP.3: 쓰기 가능한 데이터의 명시적인 공유를 최소화하라
  • CP.4: 스레드보단 작업 단위로 생각하라
  • CP.8: 동기화를 위해 volatile을 사용하지 말아라
  • CP.9: 가능한 모든 경우에, 도구 (tool) 를 이용하여 자신의 병행 실행 코드를 검증하라

Concurrency

  • CP.20: lock()/unlock() 대신 RAII를 사용하라
  • CP.21: 복수의 mutex 획득을 위해서는 std::lock() 이나 std::scoped_lock 을 사용하라
  • CP.22: lock 을 사용 중일 때는 알 수 없는 코드를 호출하지 말아라(예: callback)
  • CP.23: join 하는 thread를 유효범위 안의 컨테이너처럼 생각하라
  • CP.24: thread를 전역 컨테이너처럼 생각하라
  • CP.25: std::thread 보다는 gsl::joining_thread 사용을 우선하여 고려하라
  • CP.26: 스레드를 detach() 하지 말아라
  • CP.31: 스레드들 간의 작은 데이터 전달은 참조나 포인터보다는 값으로 전달하라
  • CP.32: 관련 없는 thread간의 소유권 공유는 shared_ptr를 사용하라
  • CP.40: 문맥 교환을 최소화하라
  • CP.41: 스레드 생성과 소멸을 최소화하라
  • CP.42: 조건 없이 wait하지 말아라
  • CP.43: 임계 영역(Critical Section)에서의 시간을 최소화하라
  • CP.44: lock_guard과 unique_lock에는 이름을 붙여라
  • CP.50: mutex 를 보호(guard) 해야 하는 데이터와 함께 선언하라. 가능한 경우에는 synchronized_value<T> 를 사용하라

Parallelism

  • 적합하다고 판단되면, 표준 라이브러리의 병렬 알고리즘들을 사용하라.
  • 병렬성을 위해 설계된 알고리즘들을 사용하라. 불필요한 의존성을 지닌 알고리즘을 사용하지 말아라.

Message passing

  • CP.60: 동시적인 작업으로부터 반환값을 받는데 future를 사용하라
  • CP.61: 동시적인 작업을 생성하기 위해선 async()를 사용하라

Vectorization

Lock-free programming

  • CP.100: 정말 필요할 때만 lock-free 프로그래밍을 사용하라
  • CP.101: 하드웨어/컴파일러 조합을 불신하라
  • CP.102: 문헌을 세심하가 공부하라
  • CP.110: 초기화를 위한 독자적인 이중 확인 잠금 (double-checked locking) 코드를 작성하지 말라
  • CP.111: 이중 확인 잠금이 꼭 필요할 경우에는 전통적인 패턴을 사용하라

Etc

  • CP.200: volatile은 C++가 아닌 메모리에 대해서만 사용하라
  • CP.201: ??? 시그널

Classs and Class Hierarchies

  • C.1: 관련된 데이터를 조직화 하라 (structclass)
  • C.2: 타입이 불변조건을 가진다면, class를 사용하라; 데이터 멤버들에 대한 제약이 자유롭다면 struct를 사용하라
  • C.3: 클래스를 사용해 인터페이스와 구현을 분리하라
  • C.4: 클래스에 직접적으로 접근할 필요가 있는 경우에만 함수를 멤버함수로 작성하라
  • C.5: 보조 함수들은 관련 클래스와 같은 namespace에 배치하라
  • C.7: 클래스 또는 열거형에 대한 정의와 변수 선언을 같은 구문에 넣지 말아라
  • C.8: non-public 멤버가 있다면 struct보단 class를 사용하라
  • C.9: 멤버들의 노출을 최소화하라

C.concrete: Concrete types

  • C.10: 클래스 계층 보다 실제(Concrete) 타입들을 선호하라
  • C.11: 실제 타입들은 정규적으로 만들어라

C.ctor: Constructors, assignments, and destructors

  • C.20: 기본 연산을 정의하지 않아도 되면 그렇게 하라
  • C.21: 기본 연산을 정의 하거나 =delete 로 선언했다면, 나머지 모두 정의하거나 =delete하라
  • C.22: 기본 연산들을 서로 조화롭게 동작해야 한다
  • C.30: 개체가 없어질 때, 명시적인 동작이 필요할 경우 소멸자를 정의하라
  • C.31: 클래스가 획득한 모든 자원은 소멸자에서 해제되어야 한다
  • C.32: 클래스가 포인터(T*)나 참조(T&)를 가지고 있다면, 참조 대상을 소유하고 있는지를 고려하라
  • C.33: 클래스가 포인터로 대상을 소유하고 있다면, 소멸자를 정의하라
  • C.35: 상위 클래스의 소멸자는 공개된 가상 소멸자 혹은 상속되는 비-가상 함수여야 한다
  • C.36: 소멸자는 실패해선 안된다
  • C.37: 소멸자를 noexcept로 작성하라
  • C.40: 클래스가 불변 조건을 가진다면 생성자를 정의하라
  • C.41: 생성자는 완전히 초기화된 개체를 생성해야 한다
  • C.42: 생성자가 유효한 개체를 생성하지 못한다면, 예외를 던지도록 하라
  • C.43: 복사 가능한 클래스(값 타입)는 반드시 기본 생성자를 갖도록 하라
  • C.44: 기본 생성자는 가능한 단순하고 예외를 던지지 않도록 하라
  • C.45: 멤버를 초기화 하기만 하는 기본 생성자는 정의하지 마라; 대신 멤버들이 스스로 초기화 하도록 하라
  • C.46: 단일 인자를 사용하는 생성자는 explicit으로 선언하라
  • C.47: 멤버 변수들은 선언된 순서대로 초기화하라
  • C.48: 상수 초기화는 가능한 클래스 내(in-class) 멤버 초기화를 사용하라
  • C.49: 생성자 안에서의 대입 보다는 초기화를 선호하라
  • C.50: 초기화 과정에서 virtual 동작이 필요하다면, 팩토리 함수를 사용하라
  • C.51: 클래스의 모든 생성자들을 위한 일반적인 동작을 표현할 때는 대리 생성자를 사용하라
  • C.52: 추가적인 초기화가 필요하지 않은 파생된 클래스에서 생성자를 사용할 때는 상속 생성자들을 사용하라
  • C.60: 복사연산을 virtual로 만들지 말아라. 매개변수는 const&로 받고, const&로 반환하지 말아라
  • C.61: 복사 연산은 복사를 수행해야 한다
  • C.62: 복사 연산은 자기 대입에 안전하게 작성하라
  • C.63: 이동 연산은 virtual로 만들지 말아라, 매개변수는 &&를 사용하고, const&로 반환하지 말아라
  • C.64: 이동 연산은 이동을 수행해야 하며, 원본 개체를 유효한 상태로 남겨놓아야 한다
  • C.65: 이동 연산은 자기 대입에 안전하게 작성하라
  • C.66: 이동 연산은 noexcept로 만들어라
  • C.67: 다형적인 클래스는 복사를 제한해야 한다
  • C.80: 기본 의미구조(semantic)를 명시적으로 사용하려면 =default를 사용하라
  • C.81: 기본 동작을 (대안을 원하지 않고) 금지하고 싶다면 =delete를 사용하라
  • C.82: 생성자 또는 소멸자에서 가상 함수를 호출하지 말아라
  • C.83: 값 타입들에는, noexcept swap함수를 제공하는 것을 고려하라
  • C.84: swap 연산은 실패해선 안된다
  • C.85: swap 연산은 noexcept로 작성하라
  • C.86: ==연산자는 피연산자 타입들에 대칭적이고, noexcept로 만들어라
  • C.87: 기본 클래스에 있는 ==에 주의하라
  • C.89: hashnoexcept로 작성하라

C.con: Containers and other resource handles

  • C.100: 컨테이너를 정의할때는 STL을 따르라
  • C.101: 값 의미구조(value semantics)를 제공하라
  • C.102: 이동 연산을 제공하라
  • C.103: 초기화 리스트 생성자를 지원하라
  • C.104: 기본 생성자는 빈 컨테이너를 만들도록 하라
  • C.109: 리소스 핸들이 포인터 의미구조를 따를 경우에는, *-> 연산자를 제공하라

C.lambdas: Function objects and lambdas

  • F.50: 함수를 사용할 수 없다면 람다를 사용하라 (지역 변수를 복사하거나, 지역적으로 사용되는 함수를 작성하는 경우)
  • F.52: 지역적으로 사용되거나 알고리즘에 전달된다면 람다 캡쳐로는 참조를 선호하라
  • F.53: 반환되거나, 외부에 저장되거나, 다른 스레드로 전달하는 경우처럼 비 지역적으로 사용된다면 람다의 참조 캡쳐를 지양하라
  • ES.28: 복잡한 초기화에는, 특히 상수 변수들의 초기화에는 람다를 사용하라

C.hier: Class hierarchies (OOP)

  • C.120: 계층적인 구조를 가진 개념을 표현하기 위해서만 클래스 계층구조를 사용하라
  • C.121: 상위 클래스가 인터페이스로 사용된다면, 순수 가상 클래스로 만들어라
  • C.122: 인터페이스와 구현의 분리가 필요하다면 추상 클래스들을 인터페이스로 사용하라
  • C.126: 일반적으로 추상 클래스는 생성자가 필요하지 않다
  • C.127: 가상함수를 가진 클래스는 공개(public)된 가상(virtual) 혹은 상속되는(protected) 소멸자를 가져야 한다
  • C.128: 가상 함수들은 virtual, override, 혹은 final 중 하나만 명시해야 한다
  • C.129: 클래스 계층구조를 정의할 때는 구현 상속과 인터페이스 상속을 구분하라
  • C.130: 다형적인 클래스에서 깊은 복사를 지원하게 하려면 복사 생성/대입 보다는 가상 clone을 선호하라
  • C.131: 자잘한 getter와 setter를 사용하지 말아라
  • C.132: 이유없이 함수를 virtual로 만들지 말아라
  • C.133: protected 데이터를 지양하라
  • C.134: const가 아닌 모든 데이터 멤버들이 같은 접근 레벨을 가지도록 하라
  • C.135: 서로 다른 인터페이스를 표현하기 위해 다중 상속을 사용하라
  • C.136: 구현 특성(attribute)의 결합을 표현하기 위해 다중 상속을 사용하라
  • C.137: 지나치게 일반적인 상위 클래스를 피하기 위해 virtual을 사용하라
  • C.138: using을 사용해 상위/하위 클래스를 위한 중복 정의 집합을 만들어라
  • C.139: final은 필요한 만큼만 사용하라
  • C.140: 가상 함수와 그 구현 함수에 서로 다른 기본 인자를 사용하지 마라
  • C.145: 다형적인 개체들은 포인터와 참조를 통해 접근하라
  • C.146: 클래스 계층구조 탐색이 불가피한 경우에만 dynamic_cast를 사용하라
  • C.147: 필요한 클래스를 찾지 못한 경우가 오류에 해당하는 경우 dynamic_cast를 참조 타입에 사용하라
  • C.148: 필요한 클래스를 찾지 못한 경우가 대안으로 사용된다면 dynamic_cast를 포인터 타입에 사용하라
  • C.149: 동적 할당한 개체의 소멸을 잊지 않도록 unique_ptr 혹은 shared_ptr를 사용하라
  • C.150: unique_ptr로 소유되는 개체를 생성하기 위해서는 make_unique()를 사용하라
  • C.151: shared_ptr로 소유되는 개체를 생성하기 위해서는 make_shared()를 사용하라
  • C.152: 절대로 하위 클래스의 포인터에 상위 클래스 포인터를 대입하지 마라
  • C.153: 타입 캐스팅보다 가상 함수를 선호하라

C.over: Overloading and overloaded operators

  • C.160: 연산자를 정의할때는 전통적인 사용을 모방하라
  • C.161: 대칭적인 연산자는 비멤버 함수로 정의하라
  • C.162: 거의 동등한 연산들을 중복정의하라
  • C.163: 거의 동등한 연산들'만' 중복정의하라
  • C.164: 암묵적 형변환 연산자들을 지양하라
  • C.165: 커스터마이징이 필요하면 using을 사용하라
  • C.166: 단항 연산자 &는 스마트 포인터와 참조 체계를 따르는 경우에만 중복정의하라
  • C.167: 연산자는 전통적인 의미를 수행하는데 사용하라
  • C.168: 연산자를 중복정의는 피연산자의 네임스페이스에 하라
  • C.170: 람다를 중복 정의하고 싶다면, 제네릭 람다를 사용하라

C.union: Unions

  • C.180: union은 메모리를 절약하기 위해 사용하라
  • C.181: 표지 없는(naked) union을 사용하지 말아라
  • C.182: Tagged union 구현에는 익명 union을 사용하라
  • C.183: 타입 재해석(type punning)을 위해 union을 사용하지 말아라

Biblography

Architectural Idea

  • A.1: Separate stable from less stable part of code
  • A.2: Express potentially reusable parts as a library
  • A.4: There should be no cycles among libraries

Appendix

  • Discussion
  • Libraries
  • Modernizing
  • Tools

Constant (Con)의 번역을 조금 다듬는 방안을 건의드리니 검토 부탁드립니다.
(git을 잘 쓸 줄 몰라서 답글로 다는데, 양해해 주시면 감사드리겠습니다.)

Con
내부의 많은 개체가 값을 바꾸지 않는 프로그램이라면 해석하기가 쉬울 것이다.
-> 프로그램 내의 객체 중 그 값이 바뀔 수 없는 것이 많다면 해석하기가 쉬울 것이다.

Con.1
Exception
함수의 인자는 지역 변수로써 이를 변경하는 것 역시 지역적임을 유념하라.
-> 함수 내부의 변수는 지역 변수이므로 이를 변경하는 영향도 지역적임을 짚고 가자.

Con.2
멤버 함수가 해당 객체의 식별 가능한 상태 변경을 야기하지 않는다면 const 로 표시되어야 한다. 이는 디자인 의도를 더욱 명확하게 설명하며, 향상된 가독성과 컴파일러에 의해 검출되는 더 많은 에러를 제공할 뿐만 아니라, 때에 따라서는 최적화 기회까지도 추가적으로 가져올 수 있다.
-> 멤버 함수가 해당 객체의 상태를 변경하지 않는다면 const로 표시하도록 한다. 이렇게 하면 디자인 의도를 더욱 명확하게 드러내고, 가독성을 높이며, 컴파일러가 더 많은 오류를 잡아낼 수 있게 도우며, 때에 따라서는 최적화를 더 잘 할 수 있도록 한다.
Note
const-정확한 방식으로 라이브러리를 업데이트한다; 선호되는 장기적인 대안이다
-> 정확하게 const를 이용하도록 라이브러리를 업데이트한다; 장기적인 대안으로 좋다
Note
"const속성을 cast를 통해 해지한다 "
-> "const속성을 타입 변환(cast)을 통해 해지한다 "
Example
이 wrapper 해결책은 f() 의 선언 자체를 수정할 수 없는 경우에만 (e.g. 수정할 수 없는 라이브러리에서 제공된다거나 하는 이유로) 사용되어야 하는 방법임을 유의하라.
-> 이렇게 wrapper를 이용하는 해결책은 (라이브러리 안에 들어 있어 직접 수정할 수 없다든가 하는 이유로) f()의 선언을 수정할 수 없는 경우에만 사용해야 하는 임시방편임에 유의하라.

Con.3
Note
Do not cast away const.
-> const속성을 타입 변환을 통해 해지하지 말라.

Con.5
향상된 성능, 향상된 컴파일-시점 검사, 보장된 컴파일-시점 변환 (evaluation) 이 제공될 뿐만 아니라, 경합 조건 (race condition) 위험도 피할 수 있다
-> 성능이 향상되고, 컴파일-시점 검사가 원활해지며, 컴파일-시점 연산(evaluation)이 보장되며, 경합 조건 (race condition) 위험도 피할 수 있다

엇 댓글을 늦게 보았네요, 말씀 주신 부분은 제가 번역해 올린 부분이라 제가 A/S 하도록 하겠습니다 ㅎㅎ 다듬어 주셔서 감사합니다, 번역 참여가 처음이라 너무 직역만 한 것 같네요^^;