Effective c++ Chapter 3 & 4

56
Effective C++

description

Effective c++ Chapter 3 & 4

Transcript of Effective c++ Chapter 3 & 4

Page 1: Effective c++ Chapter 3 & 4

Effective C++

Page 2: Effective c++ Chapter 3 & 4

자원

Page 3: Effective c++ Chapter 3 & 4

자원은 언제나 소중합니다

• 쓰고 나면 제자리에동적 메모리파일 디스크립터DX에서 폰트, 브러쉬커널 오브젝트DB연결네트워크 소켓……

Page 4: Effective c++ Chapter 3 & 4

쓰고 나면 제자리에!!

Page 5: Effective c++ Chapter 3 & 4

여기서 문제

• 너님이 제대로 돌려 놓을 수 있는가? 프로그램 분기가 많이 나뉠 경우어디선가 그냥 return 해버리거나,예외 상황 발생으로 반납을 안 하고 지나가버린다던가…

Page 6: Effective c++ Chapter 3 & 4

레알 자신 있습니까?

Page 7: Effective c++ Chapter 3 & 4

남에게 맡기자

• 일을 남에게 떠넘겨요!같은 팀원에게… (퍽, 퍽퍽퍽)

Page 8: Effective c++ Chapter 3 & 4

자원 관리 객체를 만듭시다

• 자원을 알아서 할당하고 반납 해 줄 녀석을 찾습니다. 아… 제가 빵 셔틀을 찾고 있는 것은 아닙니다.

Page 9: Effective c++ Chapter 3 & 4

자원 관리 객체를 만듭시다

• 일단 메모리 관리를 보겠습니다일반적으로 가장 많이 쓰는 녀석은 스택과 힙이죠 메모리 누수 문제는 일단 동적 할당 한 녀석을 방치하는게…

Page 10: Effective c++ Chapter 3 & 4

자원 관리 객체를 만듭시다

• 동적 할당 해제를 대신 해 줄 놈 이름하야 스마트뽀인터! 사실 동적 메모리 할당하면, 할당 된 메모리 주소가 포인터에 저장 되죠. 그것처럼 포인터처럼 작동하고, 자신이 가리킬 메모리를 관리해줄 놈 그놈이 스마트 포인터 객체(!!) 입니다.

Page 11: Effective c++ Chapter 3 & 4

자원 관리 객체를 만듭시다

• 기본 아이디어객체는 생명 주기 내에서 반드시 생성자, 소멸자를 갖는다. 소멸자에서 자원 반납을 하도록 하면 어떨까?

Page 12: Effective c++ Chapter 3 & 4

자원 관리 객체를 만듭시다

• 사실 지난 학기에 많이 썼던 것… 스택을 사용한 더미 렌더러를 만들고 생성자에서 RenderBegin()소멸자에서 RenderEnd() 이와 같은 관리 아이디어라던가

Page 13: Effective c++ Chapter 3 & 4

자원 관리 객체를 만듭시다

• 스마트포인터는 이렇게 만들어요Resource Acquisition Is Initialization(RAII) 만들어진 자원을 관리 객체의 초기화에 사용std::auto_ptr<Soldier>����������� ������������������  pSoldier(����������� ������������������  CreateSoldier()����������� ������������������  );

Page 14: Effective c++ Chapter 3 & 4

자원 관리 객체를 만듭시다

• 스마트포인터는 이렇게 반납해요자신이 소멸되면서, 가리키던 대상에 delete를 먹입니다.

Page 15: Effective c++ Chapter 3 & 4

자원 관리 객체를 만듭시다

• std::auto_ptr<> 요 녀석은… 복제로 뻥튀기가 안 되어요.대입 하는 순간 이전 녀석은 nullptr

Page 16: Effective c++ Chapter 3 & 4

자원 관리 객체를 만듭시다

• 그래서 tr1::shared_ptr 씁니다.참조 카운팅 방식 스마트 포인터! 나를 가리키는 녀석이 하나 생길 때마다 카운터가 올라갑니다. 카운터가 0이 되면 스스로 소멸 되면서 delete를 먹이죠.간단한 형태의 Garbage Collection이네요.

Page 17: Effective c++ Chapter 3 & 4

자원 관리 객체를 만듭시다

• std도 이제 겨우 알 거 같은데 tr1은 뭔데!? http://en.wikipedia.org/wiki/C%2B%2B_Technical_Report_1현재 많이 사용 되고 있는 관행적인 것들을 표준 라이브러리로 구축하려고 만든 기술 보고서라고 합니다. 정규 표현식, 스마트 포인터, 해시 테이블, 난수발생기 뭐… 이런게 있다고 하네요.

Page 18: Effective c++ Chapter 3 & 4

자원 관리 객체를 만듭시다

• 대충 요렇게 됩니다.void����������� ������������������  func(){����������� ������������������  ����������� ������������������  ����������� ������������������  ����������� ������������������  …⋯…⋯����������� ������������������  ����������� ������������������  ����������� ������������������  ����������� ������������������  std::tr1::shared_ptr<Soldier>����������� ������������������  pSoldier(����������� ������������������  CreateSoldier()����������� ������������������  );����������� ������������������  ����������� ������������������  ����������� ������������������  ����������� ������������������  …⋯…⋯} 여기서 함수 호출 스택이 비워지면서 shared_ptr의 소멸자가 불리면서,동적 할당 된 내용물을 삭제하게 됩니다.

Page 19: Effective c++ Chapter 3 & 4

자원 관리 객체를 만듭시다

• 이름(shared_ptr)에서도 알 수 있듯이… 대입 연산자를 마구 써도…내부적으로 카운팅을 다 해 줍니다.

Page 20: Effective c++ Chapter 3 & 4

자원 관리 객체를 만듭시다

• 그런데 만능은 아니에요.소멸자 내부의 삭제 부분은 delete 치고 끝입니다.배열로 생성해 두면… 대략 난감하겠죠?! boost::scoped_arrayboost::shared_array이런 녀석들을 참고하세요.

Page 21: Effective c++ Chapter 3 & 4

복사는 어떻게 할건데!!!

• 사실 복사는 조금 까다로운 것 같아요. 신경 써야 할 경우의 수가 많은 것 같아서…

Page 22: Effective c++ Chapter 3 & 4

복사는 어떻게 할건데!!!

• 복사를 금지합시다.이를테면 Lock 같은거…복사 연산을 private으로 설정해 둡시다.

Page 23: Effective c++ Chapter 3 & 4

복사는 어떻게 할건데!!!

• 참조 카운팅 합시다.넵, shared_ptr.

Page 24: Effective c++ Chapter 3 & 4

복사는 어떻게 할건데!!!

• 내용물을 레알 복사합니다.스마트 포인터가 가리키던 내용물, 즉 메모리 내용까지 싹… 깊은 복사(Deep Copy) 합니다.

Page 25: Effective c++ Chapter 3 & 4

복사는 어떻게 할건데!!!

• 자원의 소유권을 이전합시다.넵, auto_ptr.

Page 26: Effective c++ Chapter 3 & 4

복사는 어떻게 할건데!!!

• 객체 복사 함수는 컴파일러가 만들어 줄지도 몰라요. 근데 만들어진 그 놈이 당신이 원하던 놈이 아닐지도 모릅니다. 별 수 있나요? 직접 만들어야지…

Page 27: Effective c++ Chapter 3 & 4

복사는 어떻게 할건데!!!

• tr1::shared_ptr은 삭제자 지정을 허용합니다. 삭제 시에 수행 할 함수(함수객체)를 두 번째 전달인자로 옵션으로 넣어 줄 수 있습니다.std::tr1::shared_ptr<Soldier>����������� ������������������  pSoldier(����������� ������������������  CreateSoldier(),����������� ������������������  dead����������� ������������������  );

Page 28: Effective c++ Chapter 3 & 4

복사는 어떻게 할건데!!!

• 사용자 지정 삭제자 덕분에…tr1::shared_ptr은 교차 DLL 문제를 막아줍니다.

Page 29: Effective c++ Chapter 3 & 4

복사는 어떻게 할건데!!!

• 교차 DLL객체 생성에는 A라는 DLL의 new를 썼다가…객체 삭제에는 B라는 DLL의 delete를 쓴다면!???

Page 30: Effective c++ Chapter 3 & 4

더 신경 쓸 부분

• 그런데 실제 자원에 직접 접근해야 될 API들은…?접근 가능하도록 해줘야겠네요. 연산자 오버로딩으로 그럴싸하게 래핑한다던가… 뭔가 getter property를 만들어서 쓰게 한다던가…

쓰기����������� ������������������  편하죠

안전한게����������� ������������������  제일

Page 31: Effective c++ Chapter 3 & 4

new / delete 짝 맞추기

• Test*����������� ������������������  a����������� ������������������  =����������� ������������������  new����������� ������������������  Test;delete����������� ������������������  a;����������� ������������������  

• Test*����������� ������������������  a����������� ������������������  =����������� ������������������  new����������� ������������������  Test[300];delete����������� ������������������  []����������� ������������������  a;안알랴줌

Page 32: Effective c++ Chapter 3 & 4

나의 RAII를 지켜줘!

• Resource Acquisition Is Initialization 라니깐!?자원 생성과 관리 객체에 저장은 한 큐에.

• 안 지켜주면컴파일러가 지지고 볶는 과정에서… 자원이 생성 되고, 관리 객체에 저장 되기 전에 어디론가 사라질지도.당신의 코드를 썩 믿지 마세요.

Page 33: Effective c++ Chapter 3 & 4

설계

Page 34: Effective c++ Chapter 3 & 4

설계의 원칙

• 바르게 쓰기 쉽게틀리게 쓰기 어렵게UXD에서 배운 제약조건과 안전망이 생각 납니다.

Page 35: Effective c++ Chapter 3 & 4

설계의 원칙

• 사용자가 뭔가 외워서 쓸 거라 믿지 마세요. 분명히 어디선가 빼먹거나… 깜빡 잊어버리거나… 알콜 코딩(!)하다가… 제약 조건을 적용해서 처음부터 행동을 제한합시다. 사용자가 아예 신경 쓰지 않도록 잘 래핑해서 제공하는 것도 좋죠.자원 관리 정도는 사용자가 아닌 내가 해 줍니다.

Page 36: Effective c++ Chapter 3 & 4

설계의 원칙

• 일관된 형태를 제공합시다.비슷한 기능을 하는 메소드들은 이름을 같게 해 주고요.기본 제공 타입을 최대한 흉내냅시다.다른 형태로 새로 구현 할 필요가 없다면… 하지 마세요.

Page 37: Effective c++ Chapter 3 & 4

클래스 설계의 원칙

• 케릭 룩을 뽑아내는 느낌으로…심혈을 기울여야 합니다.

Page 38: Effective c++ Chapter 3 & 4

고려할 점• 생성 소멸은 어떻게?

• 초기화와 대입 차이는 어떻게?

• 복사 생성자를 신경써야지

• 가질 수 있는 값에 대한 제약 조건은?

• 기존에 있던 클래스들과의 상속 관계는?

• 어떤 종류의 형변환을 허락할 건지?이어집니다…

Page 39: Effective c++ Chapter 3 & 4

고려할 점• 어떤 연산자나 함수가 있어야 될까?

• 표준 함수들 중 어떤 것을 private로?

• 더불어, 새로운 멤버들은 public? protected? private?

• 실제로 필요한 것은 클래스인가? 클래스 템플릿 인가?

• 정말 필요합니까!? 이게 최선인가요? 만들기 전에 잘 생각해 봅니다.

Page 40: Effective c++ Chapter 3 & 4

값 전달? 참조자 전달?

• 그 때 그 때 달라요

Page 41: Effective c++ Chapter 3 & 4

값 전달? 참조자 전달?

• 일단 Call by Value의 경우생성자와 소멸자가 뙇!또한, 복사 손실 문제 상속 받은 클래스의 경우, 부모로 전달하면 값 복사 과정에…자식 고유의 속성들은 싹둑 싹둑 잘려 나가게 됩니다.

Page 42: Effective c++ Chapter 3 & 4

값 전달? 참조자 전달?

• 일단 Call by Value의 경우STL 반복자나, 함수 객체 타입, 객체의 타입이 기본 제공 타입일 때에는 Call by Value도 좋아요.단, 타입 크기가 작다고 해서 마구 남발해도 된다는 건 아닙니다.

Page 43: Effective c++ Chapter 3 & 4

값 전달? 참조자 전달?

• Call by Reference의 경우 일단 참조자로 리턴 할 경우… 참조자는 어떤 실체가 있는 것에 붙이는 별칭 같은 것이죠.실체가 없는 것을 리턴하지 맙시다.

Page 44: Effective c++ Chapter 3 & 4

값 전달? 참조자 전달?

• Call by Reference의 경우 const����������� ������������������  int&����������� ������������������  Test����������� ������������������  (����������� ������������������  const����������� ������������������  int&����������� ������������������  a,����������� ������������������  const����������� ������������������  int&����������� ������������������  b){����������� ������������������  ����������� ������������������  ����������� ������������������  ����������� ������������������  ����������� ������������������  ����������� ������������������  return����������� ������������������  &(a����������� ������������������  *����������� ������������������  b);}마치 이런 느낌이랄까요. 뭐야 이 똥덩어리는…

Page 45: Effective c++ Chapter 3 & 4

값 전달? 참조자 전달?

• Call by Reference의 경우 곰곰히 살펴보니, SM9께서 누누히 강조한 것이 떠오릅니다.함수 내부에서 만든 지역변수는 스택과 함께 사라질지니… 그거 포인터 리턴하면 너님 아웃! 함수 내부에서 함부로 new 한거 리턴하면,그거 불러온 놈이 외부에서 delete 한다는 보장 있나? 아웃!

Page 46: Effective c++ Chapter 3 & 4

값 전달? 참조자 전달?

• Call by Reference의 경우 정적 객체를 리턴 받을 경우에는…동시에 두 군데 이상에서 참조한다면 조심해야 합니다. 한 줄의 수식에서 두 번 사용 된다던가(== 비교 등)멀티 스레드 환경에서 코딩한다던가.

Page 47: Effective c++ Chapter 3 & 4

값 전달? 참조자 전달?

• 결국 생각을 많이 해야 됩니다. OTL

Page 48: Effective c++ Chapter 3 & 4

p… private!!!!!!

• 멤버 변수는 private로 하세요. 멤버 변수를 외부에서 건드리면 안 되잖아요? 접근 권한은 멤버 함수에게 양보하세요.

Page 49: Effective c++ Chapter 3 & 4

p… private!!!!!!

• protected도 그리 안전하지 않다네요. 일단 상속 받은 클래스들이 주렁 주렁 달리면… 뭐 그렇다고 합니다.

Page 50: Effective c++ Chapter 3 & 4

p… private!!!!!!

• 멤버 함수도 많아지면 외부와의 결합이 강해진다네요. 그놈의 캡슐화 때문에… 문제입니다.객체지향은 응집을 높게 하고 결합을 낮춰야 한다죠? 멤버 함수가 많아질수록내가 내 클래스를 맘대로 바꿀 수 없게 됩니다.다른 사람들이 내 클래스를 갖다 쓸텐데…맘대로 바꿨다가 대체 어떻게 수정해야 할지 모르게 되는 사태가…

Page 51: Effective c++ Chapter 3 & 4

p… private!!!!!!

• 비멤버 함수로 둘 수 있는 것들은… 같은 namespace로 묶어 둘 수 있다고 합니다.서로����������� ������������������  다른����������� ������������������  헤더나����������� ������������������  cpp����������� ������������������  파일들에����������� ������������������  분산시켜����������� ������������������  놓고도매우����������� ������������������  편리하게����������� ������������������  묶어서����������� ������������������  관리����������� ������������������  할����������� ������������������  수����������� ������������������  있는����������� ������������������  마법����������� ������������������  같은����������� ������������������  namespace!! 이번에����������� ������������������  우리����������� ������������������  프로젝트에도����������� ������������������  뭔가����������� ������������������  적용����������� ������������������  해����������� ������������������  보고����������� ������������������  싶어요…⋯

Page 52: Effective c++ Chapter 3 & 4

p… private!!!!!!

• 아무튼 비멤버 함수를 잘 써야 한다네요. 어떤 함수의 매개인자를 타입 변환 할 필요가 있다면 비멤버 함수로 만들라고 합니다. 클래스 안에 멤버 함수로 만들었다가 뭔가 형변환이 내가 원한대로 안 되는 문제가 발생하기도 한합니다. 결국은 모호할 수 있는 상황을 명확하게 만드는 것이 해결책

Page 53: Effective c++ Chapter 3 & 4

std::swap

• 솔직히 잘 모르겠어요!필요한 경우에 멤버 함수와 비멤버 함수로 swap을 구현해두라는 것 같습니다. 그리고 std::swap을 using 선언 해 주고네임스페이스를 한정 짓지 말고 swap()을 호출하면? 내가 구현한 것과 std::swap이필요할 때마다 적절하게 쓰인다는 것 같네요.

Page 54: Effective c++ Chapter 3 & 4

std::swap

• 템플릿을 부분적으로 특수화 시키랍니다. 그렇다고 이런 건 하지 마시고요.namespace����������� ������������������  std����������� ������������������  {����������� ������������������  ����������� ������������������  ����������� ������������������  ����������� ������������������  template<typename����������� ������������������  T>����������� ������������������  ����������� ������������������  ����������� ������������������  ����������� ������������������  void����������� ������������������  swap(Widget<T>&����������� ������������������  a,����������� ������������������  Widget<T>&����������� ������������������  b)����������� ������������������  ����������� ������������������  ����������� ������������������  ����������� ������������������  {����������� ������������������  a.swap(b);����������� ������������������  }}

Page 55: Effective c++ Chapter 3 & 4

std::swap

• 템플릿을 부분적으로 특수화 시키랍니다. 요런 식으로…template<typename����������� ������������������  T>void����������� ������������������  Test(T&����������� ������������������  obj1,����������� ������������������  T&obj2){����������� ������������������  ����������� ������������������  ����������� ������������������  ����������� ������������������  using����������� ������������������  std::swap;����������� ������������������  ����������� ������������������  ����������� ������������������  ����������� ������������������  template<typename����������� ������������������  T>����������� ������������������  ����������� ������������������  ����������� ������������������  ����������� ������������������  swap(obj1,����������� ������������������  obj2);}

std::swap을 이쪽으로 끌어들이고

T타입 전용의 swap을 호출하게 합시다.

Page 56: Effective c++ Chapter 3 & 4

감사합니다.