More Effective C++ 1,2
포인터와 참조자를 구분하자
* 포인터는 널 포인터가 있다.
& 참조자는 널 참조자 같은 건 없다.
** 참조자로 널 포인터를 가진 변수를 지정하지 말 것!!
포인터를 쓸 때는 null test를 해야 한다.
참조자는 할...
C++ 스타일의 캐스트를 사용하자
c++ 스타일 cast에는 네 종류가 있다.
const를 떼어주는 const_cast (volatile 도 떼어줌)
보통 사용하는 형변환인 static_cast
상속계층 구조를 오갈 때...
배열과 다형성은 같은 수준으로 놓고 볼 것이 아니다.
A라는 클래스를 담아 두는 배열과
이 배열을 매개변수로 받아 실행되는 함수 Func가 있다고 하자.
(Func는 for문을 돌며 배열을 탐색)
이 자체는 큰 문제가 ...
쓸데 없는 기본 생성자는 그냥 두지 말자
기본 생성자가 있으므로 멤버 변수 중 일부는 엉뚱하게 초기화 될 수 있다.
특히 반드시 특정 변수에 값이 필요한 클래스라면 문제가 될 수 있다.
그렇지만 기본 생성자가 없다면
1...
사용자 정의 타입 변환 함수는 주의해서 쓰자
암시적 타입변환 함수에는 두 가지가 있다.
물론 둘 다 문제를 안고 있다.
암시적 타입 변환 연산자
클래스 A에 operator double () const 함수를 추가했을 ...
증가 및 감소 연산자의 전위/후위 형태를 반드시 구분하자
일반적인 전위/후위 연산자의 내부 형태
전위
UPint& operator++() {
*this += 1;
return *this;
}
후위
const UPInt ...
&& || , 는 연산자 오버로딩 대상이 절대로 아니다!!
boolean 표현식을 평가할 때 단축평가라는 것을 한다.
표현식의 일부로 참, 거짓을 판명할 수 있으면 평가를 그만두는 것이다.(굳이 전체를 확인하지 않
아도...
new와 delete의 의미를 정확히 구분하고 이해하자
new 연산자의 동작은 두 단계이다.
1. 요청한 타입의 객체를 담을 수 있는 크기의 메모리 할당
2. 그 객체의 생성자 호출
new 연산자는 operator ne...
Upcoming SlideShare
Loading in …5
×

모어 이펙티브 c++ 1,2장 스터디

401 views
289 views

Published on

모어 이펙티브 c++ 1,2장 스터디

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

  • Be the first to like this

No Downloads
Views
Total views
401
On SlideShare
0
From Embeds
0
Number of Embeds
5
Actions
Shares
0
Downloads
4
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

모어 이펙티브 c++ 1,2장 스터디

  1. 1. More Effective C++ 1,2
  2. 2. 포인터와 참조자를 구분하자 * 포인터는 널 포인터가 있다. & 참조자는 널 참조자 같은 건 없다. ** 참조자로 널 포인터를 가진 변수를 지정하지 말 것!! 포인터를 쓸 때는 null test를 해야 한다. 참조자는 할 필요 없다. 초기화할 때 반드시 누군가를 가리키도록 되어있으므로 operator [] 를 쓸 때는 꼭 참조자를 쓰도록 하자 어떤 사용자 지정 타입 v가 있다고 할 때, v[5] = 10; 은 우리 눈에 익숙하지만 *v[5] = 10; 은 좀 이상하니까!!
  3. 3. C++ 스타일의 캐스트를 사용하자 c++ 스타일 cast에는 네 종류가 있다. const를 떼어주는 const_cast (volatile 도 떼어줌) 보통 사용하는 형변환인 static_cast 상속계층 구조를 오갈 때 사용하는 dynamic_cast 함수 포인터 타입을 강제로 바꿀 때 쓰는 reinterpret_cast c스타일 캐스트는 제약 없이 바꿔버리며 dynamic_cast같은 건 흉내만 낼 수 있을 뿐 한계가 있다. 될 수 있다면 c++ 스타일 캐스트를 사용하자. 하지만 될 수 있다면 cast가 없는 코드를 만들자!! (ec++ 항목 27 참조)
  4. 4. 배열과 다형성은 같은 수준으로 놓고 볼 것이 아니다. A라는 클래스를 담아 두는 배열과 이 배열을 매개변수로 받아 실행되는 함수 Func가 있다고 하자. (Func는 for문을 돌며 배열을 탐색) 이 자체는 큰 문제가 없다. 하지만 A를 상속받은 B클래스의 배열을 Func의 매개변수로 넘기게 되면 문제가 된다. for문을 돌 때 ++i를 하게되는 데, 상속받은 B는 A보다 크기가 클 것이므로..(최소한 vptr, vtbl..) 반복문은 미정의 동작 속으로..
  5. 5. 쓸데 없는 기본 생성자는 그냥 두지 말자 기본 생성자가 있으므로 멤버 변수 중 일부는 엉뚱하게 초기화 될 수 있다. 특히 반드시 특정 변수에 값이 필요한 클래스라면 문제가 될 수 있다. 그렇지만 기본 생성자가 없다면 1. 배열 생성시 일일이 지정해 주어야 하는 문제가 있다. 2. 배열에 포인터를 써서 저장하고 new하는 방법을 쓰면 불필요한 포인터의 메모리가 낭비될 수 있다 (요즘 같은 상황에서 이게 딱히 문제인지는 모르겠다..) 3. 기본 생성자가 없는 가상 기본 클래스일 경우 생성되는 객체의 매개변수를 자식 클래스에서 미리 알고 제공해주어야 한다. 기본 생성자를 만들자니 멤버 변수가 제대로 초기화 되었는지를 모르겠고 안 만들자니 각종 문제가 따른다. 결론은 멤버 변수를 잘 초기화 하자! 상속도 안 할거고 기본 생성자가 굳이 필요도 없는 클래스라면 기본 생성자를 만들지 말자.
  6. 6. 사용자 정의 타입 변환 함수는 주의해서 쓰자 암시적 타입변환 함수에는 두 가지가 있다. 물론 둘 다 문제를 안고 있다. 암시적 타입 변환 연산자 클래스 A에 operator double () const 함수를 추가했을 경우 의도치 않은 동작을 할 수 있다. A a; cout << a ; 일 경우 A에 operator <<이 없더라도 알아서 double로 형변환해서 출력할 수 있다. 단일 인자 생성자 Array<int> 를 만들었는데 Array에 단일인자 생성자인 Array(int size)가 있다고 할 때 if ( a == b[i] ) 와 같이 잘못 쓴 구문도 내부적으로 a == static_cast<Array<int>>(b[i])로 형변환 돼서 별다른 오류 메세지 없이 실행될 수 있다. explicit 키워드를 사용해서 암시적 타입변환을 방지하자!! (그래도 명시적 타입변환은 가능함..)
  7. 7. 증가 및 감소 연산자의 전위/후위 형태를 반드시 구분하자 일반적인 전위/후위 연산자의 내부 형태 전위 UPint& operator++() { *this += 1; return *this; } 후위 const UPInt operator++(int) { // 전위, 후위 구분을 위해 매개변수를 사용(그래서 변수명이 없음) const UPInt oldValue = *this; ++(*this); //전위 연산자로 후위 연산자를 구현 return oldValue; } 후위 연산자에 const가 붙는 이유는 i++++ 같은 사태를 방지하기 위해서이다. (첫번째 ++에서 반환된 임시 변수의 값이 증가하기 때문에..) 후위는 비용이 전위에 비해 크며(수수께끼는 모두 풀렸다..) 전위 연산자로 후위 연산자를 구현한다는 것을 기억하자
  8. 8. && || , 는 연산자 오버로딩 대상이 절대로 아니다!! boolean 표현식을 평가할 때 단축평가라는 것을 한다. 표현식의 일부로 참, 거짓을 판명할 수 있으면 평가를 그만두는 것이다.(굳이 전체를 확인하지 않 아도 되므로) if ( (p != 0 ) && (strlen(p) > 10)) 이런 식에서 p가 null이면 strlen은 호출도 되지 않는 것. 근데 && || 를 오버로딩 하면 이들이 함수호출 의미구조로 변하게 된다. 이렇게 되면 문제는 1. 함수는 매개변수 값을 알아야 하므로 결국 strlen도 수행해보고 평가한다는 것. 비용 상승!! 2. 매개 변수를 어떤 순서로 평가할지에 대해 명확하지 않다!! 쉼표는 for문 같은 곳에서 여러 문장을 수행되게 하는데 이 역시 오버로딩하면 순서보장이 안되기 때문에 곤란하다..(왜??)
  9. 9. new와 delete의 의미를 정확히 구분하고 이해하자 new 연산자의 동작은 두 단계이다. 1. 요청한 타입의 객체를 담을 수 있는 크기의 메모리 할당 2. 그 객체의 생성자 호출 new 연산자는 operator new를 호출하는데 이는 다음과 같이 선언된다. void * operator new(size_t size) // 초기화 되지 않은 원시 메모리의 포인터를 반환 operator new가 하는 일은 메모리를 할당하는 것 뿐, 생성자를 호출할 수는 없다. but 메모리 지정new는 할 수 있다. new (buffer) Widget(widgetSize) 라고 하면 buffer라는 위치에 객체를 생성하고 생성자를 호출한 다. 따라서 메모리할당과 생성자 호출을 나눌 수 있다. → alignment error 해결할 때 사용한 방식 메모리 지정 new를 delete할 때는 소멸자를 호출하고 메모리를 해제하면 된다. pw->~Widget() free(pw)식으로.. 배열을 delete할 때는 delete[] pw 식으로 하자.(ec++ 내용참고)

×