EC 789

256 views

Published on

Published in: Education
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total views
256
On SlideShare
0
From Embeds
0
Number of Embeds
3
Actions
Shares
0
Downloads
2
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

EC 789

  1. 1. 항목 41 : 템플릿 프로그래밍의 천릿길도 암시적 인터페이스와 컴파일 타임 다형성부터
  2. 2. 클래스와 템플릿은 인터페이스와 다형성을 제공하지만 그 특성이 다르다. 클래스의 경우 소스코드를 통해 인터페이스의 확인이 되는 명시적 인터페이스를 제공하지만 템플릿의 경우 정의된 typename이 지원해야 하는 표현식의 조건만 확인할 수 있는 암시적 인터페이스를 제공 클래스의 경우 다형성에 있어서 런타임 시에 함수 테이블을 통해 호출할 함수가 정해지는 런타임 다형성을, 템플릿의 경우 호출될 함수가 컴파일 시에 결정되는 컴파일 타임 다형성을 제공
  3. 3. 항목 42 : typename의 두 가지 의미를 제대로 파악하자
  4. 4. 기본적으로 템플릿에서 사용하는 class와 typename에는 차이가 없다. 하지만 typename을 써야 할 때가 있는데 그 경우는 템플릿 안에서 중첩의존이름을 사용할 때 중첩의존이름이란 C::iterator 와 같이 C라는 템플릿에서 선언된 타입에 의존해서 ::iterator를 사용하는 경우 하지만 typename을 사용하지 않아야 하는 경우도 있는데 상속되는 기본 클래스 리스트에서와 멤버 초기화 리스트 안에서는 사용하지 않는다. 참고로 이렇게 중첩의존이름의 경우 자연스레 이름자체가 길어지고 앞에 typename까지 붙여서 써야 하므로 간단하게 typedef로 사용하면 편하다.
  5. 5. 항목 43 : 템플릿으로 만들어진 기본 클래스 안의 이름에 접근하는 방법을 알아 두자
  6. 6. 템플릿은 특정 타입에 대해서만 다른 동작을 하는 버전을 만들 수 있고 이를 완전 템플릿 특수화라 한다. 템플릿 클래스를 상속 받는 경우 특수화된 템플릿 클래스가 존재할 수 있으므로 상속 받은 클래스에서 기본 템플릿 클래스의 특정 함수가 존재한다는 보장을 할 수 없다. 그래서 템플릿을 상속받아서 기본 클래스에 있는 특정 함수를 호출하고자 한다면 함수 호출 앞에 this-> 를 붙이거나 using namespace template<class>::function; 같이 유효 범위를 추가한다. 만약 컴파일 과정에서 위의 함수 호출이 불가능한 상태라면 에러가 발생해서 확인할 수 있다.
  7. 7. 항목 44 : 매개변수에 독립적인 코드는 템플릿으로부터 분리시키자
  8. 8. 템플릿 클래스에서 타입 매개변수가 다르면 사실상 같은 함수라도 각각의 타입 매개변수에 따라 따로 생성된다. 이는 자칫 하는 일은 같은 코드가 중복되는 일이 생길 수 있다. 그래서 템플릿 클래스 안에서 정의된 함수들 가운데 타입 매개변수에 의존적이지 않은 함수의 경우에는 외부로 분리해서 이를 사용하도록 해서 중복 코드를 줄일 수 있다. 이를 해결할 수 있는 방법 중 하나는 공통된 작업을 하는 기본 클래스를 만들고 이를 상속받은 클래스가 작업에 필요한 데이터의 포인터를 기본 클래스가 가질 수 있도록 한 다음 기본 클래스의 함수를 호출해서 작업을 처리하는 것이다. 하지만 타입에 따라 따로 함수를 만드는 방식과 비교하면 최적화라는 측면에서 이 방법은 약간의 손해를 볼 수 있다. 하지만 실행 코드가 작아짐으로써 페이지 폴트의 횟수를 줄일 수 있는 기회가 생기며 어느 것이 이득인지는 상황에 따라 다르다.
  9. 9. 항목 45 : “호환되는 모든 타입”을 받아들이는 데는 멤버 함수 템플릿이 직방!
  10. 10. 같은 템플릿을 통해 만들어진 객체라 하더라도 타입 매개변수가 다르면 그 객체들은 아예 다른 존재들이 된다. 그래서 이들 사이에서 형변환을 하려면 직접 정의해주어야 한다. 하지만 원칙적으로 템플릿의 타입 매개변수는 “무엇이든” 될 수 있으므로 정의해 주어야 할 함수는 무한대가 된다. 그래서 이를 해결하기 위해 무한대의 역할을 수행할 수 있는 템플릿 함수를 내부 함수로 다시 이용한다. 하지만 이 경우에는 타입 매개 변수에 따라서 형변환의 가능 여부에 따라서 그 작업을 수행할 수 있도록 제약조건을 만들어 두어야 한다. 이런 방식의 접근은 생성자 및 대입 연산에서 활용될 수 있는데 대입 연산에서 주의할 점은 템플릿 함수로 대입 연산을 정의한다고 하더라도 기본 대입 연산이 선언 되어 있지 않으면 컴파일러가 이를 자동으로 생성한다. 그러므로 기본 대입 연산도 프로그래머가 직접 정의해주어야 한다.
  11. 11. 항목 46 : 타입 변환이 바람직한 경우에는 비멤버 함수를 클래스 템플릿 안에 정의해 두자
  12. 12. 템플릿 인자 추론 과정에서는 암시적 타입 변환을 고려하지 않는다. 이런 특징에서 발생하는 문제를 해결하기 위해서 클래스 외부에 템플릿 함수를 만들어두고 템플릿 클래스 안에서 이 함수를 프렌드 클래스로 등록해서 사용하는 방법이 있다. 이때 프렌드 함수를 등록할 때는 선언만 하는 것이 아니라 정의까지 하거나 외부의 템플릿 함수를 호출하는 방식으로 구현해야 한다.
  13. 13. 항목 47 : 타입에 대한 정보가 필요하다면 특성정보 클래스를 사용하자
  14. 14. 템플릿은 타입 매개 변수가 무엇이든 가리지 않으므로 구현 과정에서 타입 매개 변수에 따라서 다른 동작을 보장해야 한다면 그 타입을 확인 할 수 있어야 한다. 이를 위해서 사용하는 것이 특성정보 클래스이다. 바로 타입 매개 변수의 특성을 확인하고, 그 특성에 맞는 작동을 하도록 구현하는 것이다. 이때 템플릿은 컴파일 단계에서 구현된다는 점을 이용해서 이 특성 확인을 런타임에 하지 않고 컴파일 타임에 할 수 있도록 하면 런타임 때의 성능을 높일 수 있다.
  15. 15. 항목 48 : 템플릿 메타프로그래밍, 하지 않겠는가?
  16. 16. 템플릿이 C++에 추가되면서 이 템플릿을 이용한 다양한 가능성을 발굴되었는데, 이 가능성을 활용하는 것이 템플릿 메타프로그래밍이다. 템플릿 메타프로그래밍의 장점은 런타임 시에 해야 할 작업을 컴파일 작업 과정으로 가져와서 실제 프로그래밍이 실행되는 성능을 향상시킬 수 있다는 점과 마치 함수형 프로그래밍과 같이 기존의 C++ 프로그래밍으로는 하기 어려운 작업들을 쉽게 할 수 있는 점이 있다.
  17. 17. 항목 49 : new 처리자의 동작 원리는 제대로 이해하자
  18. 18. new의 기본적인 역할은 필요한 공간만큼의 메모리 공간을 할당하고, 이 할당된 메모리 주소를 반환하는 것이다. 하지만 메모리 할당이 제대로 되지 않으면 예외를 던지는데(안 던지는 new도 있다) 이 에러 처리 함수를 new-handler라고 한다. 그리고 이 new-handler는 직접 다른 함수를 정의하고 바꿔 줄 수 있는데, 이때 사용하는 함수가 set_new_handler 함수이다. 이 함수의 특징은 인자로 넣은 새로운 new_handler를 new의 new-handler로 등록하고 기존에 등록되어 있는 new-handler를 반환하는 것이다. 예외를 던지지 않는 new에는 한계가 있는데, 아무리 new에서 예외를 던지지 않더라고 new로 할당된 메모리에 객체를 할당하는 과정에서 예외가 발생할 수 있기 때문이다.
  19. 19. new가 기본적으로 다음 네 가지 작업 중 하나는 반드시 해야 한다. 사용할 수 있는 메모리를 더 많이 확보한다. - 현재 작업 이후에 메모리 확보를 더 쉽게 할 수 있게 하는 것 다른 new 처리자를 설치한다. - 만약 자신이 메모리 할당에 실패한다면, 이 실패를 해결해 줄 수 있는 다른 new 처리자를 불러서 메모리를 할당 new 처리자의 설치를 제거 - set_new_handler에 널 포인터를 할당해서 메모리 할당에 실패하면 예외를 던지게 한다 예외를 던진다. - bad_alloc 혹은 그로부터 파생된 예외를 던진다. 그럼 new에서는 이를 처리하지 못하므로 처음 메모리 요청한 곳까지 도달 복귀하지 않는다 - abort나 exit를 호출
  20. 20. 항목 50 : new 및 delete를 언제 바꿔야 좋은 소리를 들을지를 파악해 두자
  21. 21. new나 delete는 C++의 보편적인 요구를 만족시키기 위한 구현이 되어 있으므로 다음과 같은 경우에 맞춰서 새롭게 구현하면 성능적으로 이득을 볼 수 있을 확률이 높다. 잘못 된 힙 사용을 탐지하기 위해 - 할달되는 메모리 영역 앞 뒤로 확인 비트를 삽입 동적 할당 메모리의 실제 사용에 관한 통계 정보를 수집 - new나 delete 안에 통계 수집 관련 코드를 넣는다. 할당 및 해제 속력을 높이기 위해 - 예를 들어 미리 pool을 생성해서 메모리를 할당 받아두고, 이 pool의 주소들을 반환할 수 있다. - easy game server 의 object pool 이 이 방식 기본 메모리 관리자의 공간 오버헤드를 줄이기 위해 - 아무래도 범용 메모리 관리자는 범용성을 위해 속도는 물론이고 메모리도 더 잡아 먹는다. - 이를 특수한 경우에 대해서 작동하도록 구현하면 이를 줄일 수 있다.
  22. 22. 적당히 타협한 기본 할당자의 바이트 정렬 동작을 보장하기 위해 - 시스템 아키텍처에 따라서 바이트 정렬을 다르게 함으로써 성능향상을 가져올 수 있다. 임의의 관계를 맺고 있는 객체들을 한 군데에 나란히 모아 놓기 위해 - 한 번에 여러 객체들을 동시에 사용하는 경우가 많은 경우 이들을 연속된 메모리에 두면 페이지 폴트를 줄일 수 있다. - easy game server 의 object pool 이 이 방식 그때그때 원하는 동작을 수행하도록 하기 위해 - 프로그래머가 원하는 동작을 new 나 delete 가 해주길 원하면 이 동작을 포함하도록 직접 구현
  23. 23. 항목 51 : new 및 delete를 작성할 때 따라야 할 기존의 관례를 잘 알아 두자
  24. 24. new나 delete를 직접 구현 할 때, 기존에 이 함수들이 따르던 관례를 고려하는 것이 좋다. new의 경우에는 최대한 메모리를 할당하기 위해 노력해야 하는데 이를 무한 루프로 만든다. 메모리 할당을 못하면 new-handler를 호출해야 한다. 0바이트에 대한 요구를 만족해야 하는데 – 일반적으로 1바이트를 할당하고 주소를 반환 클래스 전용 버전에서는 예정된 크기보다 큰 메모리 할당을 요구 받을 때 적당히 처리해주어야 한다. delete의 경우에는 널 포인터를 해제하려는 경우 아무것도 하지 않아야 하며 클래스 전용 버전인 경우에는 예정보다 큰 블록을 해제 받길 요구 받을 경우를 처리해야 한다 – 표준 delete를 호출하는 등
  25. 25. 항목 52 : 위치 지정 new를 작성한다면 위치지정 delete도 같이 준비하자.
  26. 26. 위치 지정 new는 단어에서 유추하는 내용과 다르게 실제로는 추가적인 매개 변수를 받는 형태의 new를 말한다. 문제는 이런 new의 경우에는 new 작업을 성공하고 객체를 그 메모리에 만드는 과정에서 발생하는 예외에 필요한 대응을 만들어야 한다는 것이다. 그 이유는 컴파일러는 객체 생성과정에서 예외를 확인하면 메모리를 할당한 new에 대응되는 delete로 그 메모리를 해제하기 때문이다. 그러므로 위치 지정 new를 만들었다면 이와 같은 매개변수를 가지는 delete를 만들어 두어야 한다는 것이다. 그리고 다른 주의할 점은 프로그래머가 정의한 new가 기존의 표준 형태 new를 가리지 않도록 해야 한다는 점이다. 이를 해결하기 위해서는 각각의 표준형 new 형태의 함수를 새로 선언하고, 그 내부에서 표준형 new를 호출하도록 한다.
  27. 27. 항목 53 : 컴파일러의 경고를 지나치지 말자.
  28. 28. 컴파일러가 경고를 하는 것에는 다 이유가 있다. 무시하지 말자. 경고 수준을 최대로 두고 프로그래밍하는 것도 좋은 방법 하지만 컴파일러의 경고만 믿어서도 안 된다. 컴파일러 별로 제공하는 경고가 다를 수 있다. 결국 프로그래머가 잘해야 된다.
  29. 29. 항목 54 : TR1을 포함한 표준 라이브러리 구성요소와 편안한 친구가 되자.
  30. 30. TR1은 일종의 입법 예고와 같은 것 - 앞으로 C++에 표준으로 채용될 내용들 그 내용에는 스마트 포인터나 정규표현식과 같은 유용한 기능들이 많이 있다. 주의 할 것은 TR1은 어디까지나 명세일 뿐 구현이 아니다. 그러므로 이런 명세를 만족하는 구현을 찾아야 한다. (지금은 C++12가 나왔으니 좀 다른 이야기가 되려나)
  31. 31. 항목 55 : Boo子有親! 부스트를 늘 여러분 가까이에
  32. 32. 부스트는 C++에 강력한 영향력을 가지는 C++ 라이브러리 제작 단체 체계적인 시스템을 통해 라이브러리를 제작하고 제공하고 있으며 무료인 오픈 소스로 제공 표준에 채용되지 않은 다양한 기능들이 있으므로 참고하면 좋다.

×