관리 메뉴

HAMA 블로그

C++ 50 계명 - 이것만은 기억하자. 본문

C++ (비공개)

C++ 50 계명 - 이것만은 기억하자.

[하마] 이승현 (wowlsh93@gmail.com) 2019. 3. 19. 09:25

사족: 다시 C++을 시작 하면서 세부적이진 않지만 기본적으로 기억해 두어야할 지침 50가지를 정리해 보았습니다. C++을 처음 시작하는 개발자들에게도 도움이 되지 않을까 싶습니다. 해당 내용 회색 글자는 팀에 의해 선택될 여기가 있다고 보는 방식입니다. 기억하기 쉽도록 경구만 썼으며 자세한 내용은 구글링과 젤 마지막 레퍼런스를 통해 확인 하시길 바랍니다.

C++ 50 계명 - 이것만은 기억하자.


일반 

1. immutable / const 은 디폴트로 적극적으로 사용한다.
2. 다형성을 가진 기본 클래스는 소멸자를 반드시 가상 소멸자로 만든다.
3. 값을 그대로 매개변수로 넣지말고, 대개 상수객체 참조자로 전달한다.
4. 변수 정의를 상단에 몰아서 하지 않는다. 사용 되는 곳 근처에서~
5. 상속보다는 합성을 사용한다. 
6. warning 을 보면 자기가 없앤다. 팀원들이 보지 않게 한다. 
7. RAAI를 항상 인식하되, 표준에서 제공해주는 것으로 되는지 확인한다.
8. C++ 은 null 포인터를 삭제해도 문제가 없다. 다만 개발시 null assert 는 많으면 많을 수록 좋다.
9. C++을 사용한다면 Class 만드는 것을 겁내지 마라. 모든것을 클래스/객체로 만든다는 생각으로 코딩한다. C++ 에서 Class는 다양한 역할을 할 수 있다. 그런게 싫다면 자바,C++  하지말고 C/Golang으로 가자. (38번참조) 
10. auto/ override /nullptr / constexpr / move / forward / atomic 키워드를 사용한다.
11. namespaces를 적극적으로 사용하며, using 은 사용하지 않는다. std:: 를 직접 붙혀준다.
12. {} 중괄호 초기화를 적극적으로 이용한다. vector<int> vec(10,20); 과 vector<int> vec{10,20}; 의 차이를 구별한다.
 initializer_list 에 대해 이해한다. 

STL

13. STL을 신뢰하고 사용한다. (개인적으론 boost 도) 
14. STL 컨테이너는 쓰레드 안전하지 않다고 각인하자.  C++11에도 여전히 쓰레드 안전한 컨테이너는 없다.( http://libcds.sourceforge.net/  이런 대체제가 있다. boost에도)
15. 많은 경우 동적으로 할당한 배열보다는 vector와 string이 낫다. (std::copy가 memcpy보다 느리지 않다)
16. 정렬이 필요 없는 맵은 C++11의 unordered_map 을 사용한다.
17. 요소를 정말로 제거하고자 한다면 remove 류의 알고리즘에는 꼭 erase를 붙여 사용하자 
18. STL 알고리즘을 적극적으로 이용한다. 

Smart Pointer

19. new / delete 를 직접하는 시대는 지났다.
20. unique_ptr 를 디폴트로 사용하자. unique_ptr로 충분하게 설계하자.
21. make_shared 로 초기화 하자.(deleter 넣어줘야 할 경우 제외) 
22. shared_ptr 나 unique_ptr 사용시 raw pointer를 별개로 생성/소멸하지 말자. 
23. 배열을 스마트 포인터로 만들었을 경우 반드시 custom deleter 를 생성자에 넣어주자.
24. shared_ptr 사용시 순환 참조가 되는지 확인하자. (weak_ptr로 해결)
25. std::move 로 스마트포인터를 이동시켜야 할 경우가 있을 때 조심 조심.
26. 위의 룰을 어겨야 할 경우가 발생시 팀원들에게 알린다.

Move vs Copy

27. 이제 move가 디폴트고 copy가 쵸이스다. 항상 연구하자. move를 사용 할 순 없는지..
28.  std::move는 원본이 없어진다는 것을 의미한다. 원본이 필요 없으면 이동하자. 

Type

29. 이왕 C++ 쓰는거 타입을 구체적으로 명시하고 타입에 안전한 코딩을 한다.
30.   int8_t, int64_t, uint32_t 와 같은 구체적 표준타입을 사용한다. 
31.  std::memcpy, std::memmove, std::memset, std::memcmp, 대신해 std::copy, std::move, std::fill, and std::equal[1] 를 사용하자.타입안정적이며 성능도 더 느리지 않으며 더 나아질 여지도 있다.

예외

32. 예외/에러는 최대한 가까운 곳에서 처리한다.(참고: 예외 처리에 대한 6가지 화두)
33.   예외를 상위 전가 시키지 말고, 리턴 값으로 처리한다. 
34.  모든 리턴 값은 에러처리로 사용한다.
35.  std::optional 을 적극적으로 이용한다.

예외처리는 너무 다양한 시각이 존재하므로 팀 설계 철학에 따라 갑니다. 개인적으로는 c/golang 방식으로 최대란 리턴값으로 가까운 곳에서 처리하는게 나은거 같습니다. 아마 예외처리에 대해 전 팀원들이 충분히 숙지/약속되어 있는 상태라면 자바처럼 복잡한/강제적인 예외 시스템을 사용하는 것도 괜찮긴 합니다만..

성능

36. 섣부른 최적화는 만원의 악 
37. 직접 메모리풀/쓰레드풀을 만드는 대신 대체제가 있는지 확인하다. 직접 만들어야 할 필요가 있을 경우 철저한 테스트가 필요하다. 
38. 인라인을 항상 고려해 본다. 
39. 아주 단순한 컨테이너/알고리즘인데 STL과 아주 큰 성능상 차이가 있으며, 그 성능이 해당 솔루션의 철학에 중요하다면 그때서야 자신의 컨테이너를 만든다.
40. 객체 생성 비용에 대한 문제가 생길 수 있다는 것만 기억하되, 최적화(BMT) 전에는 신경쓰지말아라.(9번참조)

디자인패턴/리팩토링

41. 메소드의 크기를 작게하는건 기본 중의 기본. 
42. 클래스의 책임 범위를 최소화 하며, 외부에서 로직을 주입받아 사용한다.
43. 싱글턴 패턴은 가급적 사용하지 말자. 
44. 적어도 어댑터,커맨드,전략,컴포지트,옵저버패턴은 대화가 통하게 알아두자.

동시성

45. thread 보다는 task, task 보다는 추상층 높은 아키텍터 선택(Actor, CSP)
46. 락 없는 동시성 개발을 지향한다.
47. Read/Write Lock을 선택한다.
48. 이미 존재하는 쓰레드 안전한 자료구조(컬렉션)를 사용한다. 
49. 멀티쓰레드/비동기가 무조건 빠르다는 상식을 버린다.

   예) https://hamait.tistory.com/960  https://hamait.tistory.com/839

50. 표준 병렬알고리즘을 검토한다.

결론

C++을 굳이 사용한다면 그에 걸맞는 지식을 공부하라. 로우레벨을 잘 활용 할 수 있는 수많은 지식들을 익혀야하며 그 와 동시에 OOP의 철학까지 함께 익혀야하는 정말 조심스럽게 다루어야하며 공부해야할게 많은 언어이다. 트레이드 오프를 명심하라. 필자는 C++ 경력 동안 많은 코딩과 C++서적도 20권 이상 독파했지만 대부분 다른 언어/개발 하면서 그 정수를 많이 까먹었고, 미묘한 실수를 범할 여지가 있어서 다시 체득하려면 비용이 또 따를 것이다. 따라서 애초에 이런 C++에 들이는 비용(공부비용, 수동관리에 의한 오류발생 비용,각종 타이밍 버그) 을 줄여주는 Java,Go,Rust, Python,Clojure 같은 언어를 사용하여 만들어야하는 솔루션에 집중하는 시간을 늘리는게 많은 분야에서 유리하다고 본다. 속도먹는 하마 부분만 모듈화를 한다던가. 이제 C/C++만 돌아가는 환경/C/C++에 대한 자료뿐이 없는 분야/ 0.1ms의 속도라도 줄여야하는 극한의 상황이 아니고서는 다른 언어로 눈을 돌려보는게 어떨까.



레퍼런스:

https://www.acodersjourney.com/top-10-dumb-mistakes-avoid-c-11-smart-pointers/
https://www.oreilly.com/ideas/2-major-reasons-why-modern-c-is-a-performance-beast
http://www.modernescpp.com/index.php/copy-versus-move-semantic-a-few-numbers
http://maintainablecode.logdown.com/posts/159916-memcpy-memmove-and-memset-are-deprecated
Effective C++ / Effective Modern C++ / Effective STL  / Efficient C++ 

Comments