한글화 프로젝트 진행상황 공유
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
- Per.1: Don't optimize without reason
- Per.2: Don't optimize prematurely
- Per.3: Don't optimize something that's not performance critical
- Per.4: Don't assume that complicated code is necessarily faster than simple code
- Per.5: Don't assume that low-level code is necessarily faster than high-level code
- Per.6: Don't make claims about performance without measurements
- Per.7: Design to enable optimization
- Per.10: Rely on the static type system
- Per.11: Move computation from run time to compile time
- Per.12: Eliminate redundant aliases
- Per.13: Eliminate redundant indirections
- Per.14: Minimize the number of allocations and deallocations
- Per.15: Do not allocate on a critical branch
- Per.16: Use compact data structures
- Per.17: Declare the most used member of a time-critical struct first
- Per.18: Space is time
- Per.19: Access memory predictably
- Per.30: Avoid context switches on the critical path
Naming and Layout Rules
- NL.1: Don't say in comments what can be clearly stated in code
- NL.2: State intent in comments
- NL.3: Keep comments crisp
- NL.4: Maintain a consistent indentation style
- NL.5: Avoid encoding type information in names
- NL.7: Make the length of a name roughly proportional to the length of its scope
- NL.8: Use a consistent naming style
- NL.9: Use
ALL_CAPS
for macro names only - NL.10: Prefer
underscore_style
names - NL.11: Make literals readable
- NL.15: Use spaces sparingly
- NL.16: Use a conventional class member declaration order
- NL.17: Use K&R-derived layout
- NL.18: Use C++-style declarator layout
- NL.19: Avoid names that are easily misread
- NL.20: Don't place two statements on the same line
- NL.21: Declare one name (only) per declaration
- NL.25: Don't use
void
as an argument type - NL.26: Use conventional
const
notation
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의
array
나vector
를 사용하라 - SL.con.2: 다른 컨테이너를 사용할 이유가 있지 않다면 STL
vector
를 기본으로 사용하라 - SL.con.3: 경계조건에서 발생하는 에러를 피하라
String
- SL.str.1: 문자열을 제대로 소유하기 위해서는
std::string
을 사용하라 - SL.str.2: 문자들의 나열을 참조하기 위해서는
std::string_view
나gsl::string_span
을 사용하라 - SL.str.3: 0으로 끝나는 문자들의 나열인 C 스타일의 문자열을 표현하려면
zstring
나czstring
을 사용하라 - 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: 명시적인
new
와delete
호출을 지양하라 - 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::array
나stack_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: 자원을 관리하는 함수 외부에서
new
와delete
사용을 피하라 - 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:
break
와continue
의 사용을 최소화하라 - ES.78: 내용이 있는
case
는break
하라 - 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: 관련된 데이터를 조직화 하라 (
struct
와class
) - 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:
hash
는noexcept
로 작성하라
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 하도록 하겠습니다 ㅎㅎ 다듬어 주셔서 감사합니다, 번역 참여가 처음이라 너무 직역만 한 것 같네요^^;