알게된 개념 가끔 추가...
[클래스 멤버 변수 초기화]
- 생성자 내에서 멤버 변수에 값을 넣는 것은 초기화가 아닌 대입이다. 따라서 함수의 헤더에 사용하는 초기화 리스트 (initializer list)를 사용하자.
[가상 함수와 가상 테이블]
- 가상 함수들을 저장하고 있는 가상 테이블은 클래스마다 하나씩 존재하며, 객체가 할당된 메모리 상에 가상 테이블의 주소가 있다. 따라서 가상 함수가 필요하다면 객체의 메모리에서 가상 테이블의 주소를 찾아 가상 테이블로 간 뒤 가상 테이블에서 원하는 함수의 주소를 또 찾아야 한다. 따라서 가상 함수는 런타임 중 실체를 찾는 동적 바인딩이며 속도가 느리다. 하지만 C++의 다형성(Polymorphism)의 핵심 개념인 동일한 interface, 다른 behavior에 있어서 virtual은 중요한 요소이며 부모 클래스 형의 포인터에 자식 클래스의 객체 주소를 저장하고, 부모 클래스 형 포인터를 통해 자식 클래스의 멤버 함수에 동적으로 접근할 수 있게 해준다. (C++은 기본적으로 정적 바인딩이므로.. 가상 함수가 아니라면 오버라이드를 하더라도 부모 클래스의 함수가 호출 된다.)
[Linked list와 CPU 캐시는 케미가 좋지 않다]
- 링크드 리스트(list in cpp)는 중간에 삽입 및 삭제 연산이 O(1) time complexity를 가져 vector보다 삽입 삭제 연산이 많이 일어날 경우 보다 빠른 자료구조이다. 하지만 (링크드)리스트는 CPU의 캐시 기능과 friendly 할 수 없다. 캐시는 한 번 참조한 메모리의 주변 메모리가 다시 사용될 가능성이 높다고 판단하여 인접한 메모리를 캐시 메모리에 저장한다. 이렇게 참조했던 메모리의 인접 메모리를 다시 참조하는 성질을 공간적 지역성(locality)라고 한다. 그런데 연결 리스트는 불연속적인 메모리 구조를 가진다. 이는 지역성이 좋지 않아 캐시 기능과 케미가 좋지않다. 캐시 기능은 연속된 메모리를 할당하는 자료구조인 배열(vector 등)과 케미가 좋다. 실제로 벡터를 사용할 때가 더 빠른 경우가 많다고 하며, list보다 vector가 더 많이 사용된다고 한다.
[동적 할당과 메모리 단편화]
- heap 영역의 빈번한 메모리 재할당은 메모리 단편화를 초래한다. 즉 동적 할당과 해제를 자주하는 것은 좋지않다. 이를 방지하기위해 STL 컨테이너에서 reserve를 지원하는 컨테이너를 사용한다면 꼭 reserve 후 벡터를 사용하자.
[템플릿의 장단점과 용도]
- 템플릿 프로그래밍은 컴파일 시간에 적절한 타입으로 코드를 인스턴스화(복사)해주어 컴파일 시간과 코드 크기가 커질 수 있지만 런타임 시간이 적어지기 때문에 유용하게 쓰일 수 있다. 하지만 템플릿 메타 프로그래밍은 코드가 복잡하여 가독성이 떨어지고, 디버깅이 어렵다는 단점이 있다. 따라서 컨테이너와 같이 다양한 타입을 활용할 수 있을 때 주로 사용하고 적은 자료형을 다룬다면 각자 클래스를 만들자. 단, 해당 부분에 있어서 속도가 너무나도 중요하다면 템플릿을 사용하도록 한다.
[auto 키워드와 const]
- auto 키워드로 const 타입 변수를 저장할 때 auto 앞에 const를 붙여주지 않아도 자동으로 const로 받아진다. 하지만 가독성을 위해 const 타입이라면 auto 앞에 const 키워드를 붙여주자.
auto& name = GetString(); // 가독성下
const auto& name = GetString(); // 가독성上
[auto 키워드와 pointer]
- auto 키워드로 포인터 타입을 받을 때 포인터(*) 타입을 붙이지 않아도 알아서 포인터 타입으로 변환해준다. 하지만 가독성을 위해 포인터를 받으면 auto 키워드에 *을 붙여주자.
auto ptr = GetPointer(); // 가독성下
auto* ptr = GetPointer(); // 가독성上
[템플릿 특수화와 오버로딩]
- 클래스 템플릿은 오버로딩이 되지 않지만 함수 템플릿은 오버로딩이 가능하다. 클래스 템플릿은 부분 특수화 또는 완전 특수화 둘다 가능하지만 함수 템플릿은 부분 특수화는 불가능하고 완전 특수화만 가능하다. 하지만 함수 템플릿은 오버로딩을 통해 부분 특수화의 효과를 낼 수 있다.
[C++ STL map]
- C++ STL 중 map 컨테이너는 내부적으로 스스로 균형을 맞추는 red-black-tree를 사용한다. red-black-tree는 이진 탐색 트리의 일종이다.
[C++ STL std::map vs vector 정렬]
N개의 요소를 std::map 컨테이너에 대입하면 자동으로 오름차순 정렬이 된다. 하지만 N개의 요소를 vector에 저장하고 std::sort 함수를 이용하여 정렬하는 것이 훨씬 빠르다.
[copy < rvalue move < RVO]
- 함수에서 std::move를 사용하여 객체를 반환하는 비용은 단순 copy보단 낮지만 RVO보단 높다. 따라서 RVO 최적화가 가능한 상황에선 move를 통해 반환하지 말자.
[운영체제로의 진입을 위한 인터페이스]
- 운영체제가 제공하는 서비스를 이용하기 위해선 사용자 모드가 아닌 커널 모드에서 실행 가능한데, 사용자 모드에서 실행되는 응용 프로그램이 이를 사용하기 위해선 시스템 호출(system call), 인터럽트(interrupt), 예외현상(exception)을 통해서만 운영체제로의 (간접적인)진입이 가능하다.
[기본 복사 생성자 및 복사 대입 연산자 생성 조건]
- 컴파일러가 자동으로 생성해주는 default 복사 생성자 및 복사 대입 연산자는 다음 조건 중 한 가지라도 만족하면 생성되지 않는다.
- 이동 생성자가 명시적으로 선언되어 있는 경우
- 이동 대입 연산자가 명시적으로 선언되어 있는 경우
즉, 위의 경우 복사 생성자 또는 복사 대입 연산자를 구현하지 않으면 복사 생성 및 복사 대입 연산을 할 수 없다.
[기본 이동 생성자 및 이동 대입 연산자 생성 조건]
- 컴파일러가 자동으로 생성해주는 default 이동 생성자 및 이동 대입 연산자는 다음 조건 중 한 가지라도 만족하면 생성되지 않는다.
- 명시적으로 이동 생성자 및 이동 대입 연산자가 선언되어 있는 경우
- 명시적으로 복사 생성자 및 복사 대입 연산자가 선언되어 있는 경우
- 명시적으로 소멸자가 선언되어 있는 경우
즉, 위의 경우 이동 생성자 또는 이동 대입 연산자를 구현하지 않으면 이동 생성 및 이동 대입 연산을 할 수 없다.
[기본 이동 생성자 및 이동 대입 연산자 생성 조건]
deque(double ended queue)의 올바른 발음은 디큐가 아닌 덱(deck과 동일)이다.
'C,C++ > Etc' 카테고리의 다른 글
Visual Studio C++ 17 사용하도록 설정하기 (0) | 2020.06.25 |
---|---|
메모리 정렬과 패킹 (2) | 2020.05.19 |
[C++] 비트 연산자로 N번째 비트 변경하기 (0) | 2020.03.11 |
[C++] 소수점 n번째 자리에서 반올림 하기 | std::round (0) | 2020.02.26 |
내가 따라하는 C++ 코딩표준 (0) | 2020.01.02 |
댓글