ec++ 3,4 summary

37
EC++ 3,4 summary NHN NEXT 남남남

Upload: sehyeon-nam

Post on 23-Jun-2015

114 views

Category:

Internet


3 download

TRANSCRIPT

Page 1: Ec++ 3,4 summary

EC++ 3,4 summary

NHN NEXT 남세현

Page 2: Ec++ 3,4 summary

EC++ 3,4 summary

NHN NEXT 남세현

Page 3: Ec++ 3,4 summary

자원 관리• 자원 , 가장 중요한 것은 ?– “ 가져다 썼으면 해제해야 한다”

• 객체에 기반하여 자원을 관리하는 방법을 알아보자 .

Page 4: Ec++ 3,4 summary

스마트 포인터• 스마트 포인터 (auto_ptr)–소멸자가 자동으로 delete 를 실행해 줌

• 예시Character* pCh = createCharacter();VSstd::auto_ptr<Character>pCh(createCharacter());

• 단 , 복사가 자유롭지 못하다–다음장…

Page 5: Ec++ 3,4 summary

스마트 포인터• 단 , 복사가 자유롭지 못하다– 복사하는 객체만 해당 자원의 유일한 소유권을 가질 수

있다 .– 원래 포인터는 NULL 을 가리키게 된다 .

• ex)pCh1 가 캐릭터를 가리키고 있다면std::auto_ptr<Character>pCh2(pCh1); // pCh1 는 null 이 됨 . pCh2 는 pCh1 이 가리키던 객체를 가리킴pCh1 = pCh2; // 다시 pCh2 는 null 이 됨 . pCh1 은 pCh2 가 가리키던 객체를 가리킴

Page 6: Ec++ 3,4 summary

참조 카운팅 방식 스마트 포인터• 몇 명이 참조하고 있는지 숫자를 셈• 0 명이 참조하고 있으면 자동으로

객체 삭제해주는 스마트 포인터–가비지 컬렉션과 비슷함 .

• std::tr1::shared_ptr• 사용방법 auto_ptr 와 동일• 단 , 위 스마트 포인터들은 배열 객체에게는

사용하지 말 것 ! 배열 삭제 지원 안함 .

Page 7: Ec++ 3,4 summary

참조 카운팅 방식 스마트 포인터• 몇 명이 참조하고 있는지 숫자를 셈• 0 명이 참조하고 있으면 자동으로

객체 삭제해주는 스마트 포인터–가비지 컬렉션과 비슷함 .

• std::tr1::shared_ptr• 사용방법 auto_ptr 와 동일• 단 , 위 스마트 포인터들은 배열 객체에게는

사용하지 말 것 ! 배열 삭제 지원 안함 .

Page 8: Ec++ 3,4 summary

RAII 같은 객체 만들어보기• 객체를 복사하면 어떻게 해야하나 ..?–어떤 동작이 이루어져야 하는지 혼돈의카오스

1. 복사를 금지한다 .– 복사 연산을 private 멤버로 만듬 .

2. 관리하는 자원에 대해 shared_ptr 사용3. 아예 깊은 복사를 해줘라4. 소유권을 아예 넘겨줘라 (auto_ptr 처럼 )

Page 9: Ec++ 3,4 summary

RAII 같은 객체 만들어보기• 객체를 복사하면 어떻게 해야하나 ..?–어떤 동작이 이루어져야 하는지 혼돈의카오스

1. 복사를 금지한다 .– 복사 연산을 private 멤버로 만듬 .

2. 관리하는 자원에 대해 shared_ptr 사용3. 아예 깊은 복사를 해줘라4. 소유권을 아예 넘겨줘라 (auto_ptr 처럼 )

Page 10: Ec++ 3,4 summary

RAII 같은 객체 만들어보기• 난 이렇게 호출하고 싶은데요 ?– int hp = GetHP(pCh);–에러 ! pCh 는 Character* 가 아니라

tr1::shared_ptr<Character> 타입이라서…• Get 이라는 멤버 함수 하나 만들자 !– Character* GetHP() { return hp_; }

• 혹은 암시적 변환 함수를 사용하자– Operator Character() const { return ch; }Ex ) LevelUpCharacter(pCh, 22);

Page 11: Ec++ 3,4 summary

New, Delete

• delete 와 delete[ ] 는 다르다 !– std::string *stringPtr1 = new std::string;– std::string *stringPtr2 = new

std::string[9];– delete stringPtr1;– delete [] stringPtr2;

• 대개 배열 원소의 개수가 힙 메모리에 들어가기 때문 !

• 그냥 vector 사용합시다…

Page 12: Ec++ 3,4 summary

조심 !

• New 로 생성한 객체를 스마트 포인터에 넣는 코드는 별도의 한 문장으로 합시다 !

• processSomething(std::tr1:::shared_ptr<Character>(new Character), createSomething()); 이런거 하지 말자구요 !

• 이유 : 컴파일러 제조사마다 param func 의 호출 순서가 다름 .디버깅 무지무지 힘들어짐 .

• So,std::tr1:::shared_ptr<Character> pCh(new Character);processSomething( pch, createSomething() );

Page 13: Ec++ 3,4 summary

인터페이스• ‘ 제대로 쓰기엔 쉽게 , 엉터리로 쓰기엔 어렵게 !’• Class … Date(int month, int day, int

year)– Date d(30, 3, 1995);– Date d(3, 40, 1995);–둘 다 그래선 안되는데… 에러는 안남 !

• Struct Day, Month, Year– Date d(Month(3), Day(30), Year(1995));

• 사람이 실수 하지 않도록 도와주자 .

Page 14: Ec++ 3,4 summary

실수 , 실수 , 실수 ! 줄여보자 !!

• Investment* createInvestment();• 가능한 실수–포인터 삭제를 잊어버리거나– Delete 를 두 번 이상 해버리거나

• 스마트 포인터를 반환시켜보자• std::tr1:shared_ptr<Investment> createInvest-

ment();

• 삭제하는것을 깜빡해도 불상사 X

Page 15: Ec++ 3,4 summary

자원 삭제하는 함수는 어떄 ?

• getRidOfInvestment 라는 함수• 깔끔해 보이지만…–저 함수가 있다는 것을 까먹고 delete 쓰면 ..?

• getRid…ment 와 tr1::shared_ptr 를 묶자 !

• std::tr1::shared_ptr<Investment> pInv( static_cast<Investment*>(0), getRidOfInvest-

ment );

• 저 함수를 createInvestment 에서 실행 !

Page 16: Ec++ 3,4 summary

tr1::shared_ptr 의 장점• 교차 DLL 문제–객체 생성시 DLL 의 new 를 사용했는데

다른 DLL 의 delete 를 쓸 경우• tr1::shared_ptr 은 new 를 사용한 DLL

의 delete 를 사용하도록 구현되어 있음 .• DLL 꼬이는 문제 걱정 끝 ~!

Page 17: Ec++ 3,4 summary

잊지 말자• 좋은 인터페이스란 ?–제대로 쓰기엔 편하고–엉터리로 쓰기엔 어렵게 !

• 사용자 실수를 방지해주자 !–더이상 자원 관리 작업을 사용자 책임으로

내몰지 말자 !

Page 18: Ec++ 3,4 summary

클래스 설계를 타입 설계 하듯• 좋은 클래스의 조건 3

1. 문법이 자연스럽고2. 의미구조가 직관적이며3. 효율적인 구현

Page 19: Ec++ 3,4 summary

객체 설계 ,하나 하나 따져가면서 신경써보자

1. 객체 생성 및 소멸은 어떻게 이뤄져야 하는가 ?2. 객체 초기화는 객체 대입과 어떻게 다른가 ?–초기화랑 대입을 헷갈리지 말자 !

3. 값에 의한 전달은 어떤 것을 의미하는가 ?–값에 의한 전달을 구현하는 쪽은 복사 생성자

Page 20: Ec++ 3,4 summary

객체 설계 ,하나 하나 따져가면서 신경써보자

4. 값들에 대한 제약을 무엇으로 둘 것인가 ?– 데이터 멤버의 몇 가지 조합 값만은 반드시

유효해야 함 !

5. 기존 클래스 상속 계통에 맞출 것인가 ?– 상속할 것인가 , 멤버 함수가 가상인가

비가상인가 ...

6. 어떤 종류의 타입 변환을 허용할 것인가 ?– 필요하면 타입 변환 함수나 비명시호출 등을

구현해놓자 .

Page 21: Ec++ 3,4 summary

객체 설계 ,하나 하나 따져가면서 신경써보자

7. 어떤 연산자 , 함수를 두어야 할까 ?8. 표준 함수들 중 어떤걸 허용하지 말까 ?–무엇을 private 로 선언해야 할까 ?

9. 접근 권한을 어느 쪽에 줄 것인가 ?– public, private, protected...

Page 22: Ec++ 3,4 summary

객체 설계 ,하나 하나 따져가면서 신경써보자

10. 비선언 인터페이스로는 뭘 둘 것인가 ?11. 얼마나 일반적인가 ?–혹시 새로운 클래스를 정의하는게 아니라새로운 클래스 템플릿을 정의해야 하는건 아닌가 ?

12. 정말로 필요한가 ?– 기존 클래스 기능 아쉬워서 파생 클래스 만들고

있진 않은가 ? 그렇다면 그냥 비멤버 함수를 만들자 .

Page 23: Ec++ 3,4 summary

상수객체 참조자에 의한 전달• 값에 의한 전달–실제 인자의 ‘사본’이 전달됨–은근 고비용의 연산–복사 생성자 한 번 , 소멸자 한 번 !–멤버 변수들의 생성자들도 ... 소멸자들도 !!!

• 상수객체 참조자가 출동한다면 !?– void func(const Student& s);–생성자 , 소멸자 전혀 호출 안됨 .–복사에 의한 손실 문제도 없어짐 .

Page 24: Ec++ 3,4 summary

상수객체 참조자에 의한 전달• 기본 제공 타입들은 값으로 전달해도 좋아–크기도 작고 ... 뭐 딱히 문제는 없잖아 ?

• 크기가 작은 객체들을 값으로 넘겨도 .. 좋아 ?–안됨 .–생각보다 복사 생성자가 비쌀 수 있거든 .

• 그럼 크기도 작고 복사 생성자도 작다면 ?–어떤 컴파일러에서는 기본 제공 타입은 레지스터에 들어가지만 객체는 전혀 안들어가기도 함 . 그냥 하지마 좀 !!

Page 25: Ec++ 3,4 summary

참조자를 반환하려고 하진 마 !

const A& func(param)• 객체 생성 , 소멸에 드는 비용은 어찌하나 ?–그래 ? 참조자를 반환하면 비용 부담이 없지

않을까 ??

• 그럼 그 참조할 객체는 누가 만들건데 ...

Page 26: Ec++ 3,4 summary

참조자를 반환하려고 하진 마 !

const A& func(param){A res(param);return res;}• 생성자 부르는거 싫어서 시작한 일인데 ?–아직도 생성자가 있음 .

• res 는 지역객체인데 ?–함수 끝나면 사라짐 .

Page 27: Ec++ 3,4 summary

참조자를 반환하려고 하진 마 !

const A func(param){A *res = new A(param);return res;}• 생성자 부르는거 싫다니깐 !• 그리고 누가 delete 시켜줄건데 ?

Page 28: Ec++ 3,4 summary

참조자를 반환하려고 하진 마 !

const A func(param){static A res;res = ...return res;}• 스레드 안전성 문제• func(p1) == func(p2) 는 항상 참이오 . 헐 ...

Page 29: Ec++ 3,4 summary

참조자를 반환하려고 하진 마 !

그냥 새로운 객체를 반환시키자inline const A func(param){return A(param);}• 생성자 ... 쓰는 비용이 싫다매 ?

– 어쩔 수 없어 . 최소한의 비용이야 .

• 게다가 대부분 컴파일러에서 이런 부분은 최적화 되어있음• 제대로 돌아가게 만드는데 신경 쓰자 .• 참조가 좋다고 해서

무조건 다 참조로만 하려곤 하지 말고 !

Page 30: Ec++ 3,4 summary

DATA MEMBERSHOULD BE in PRIVATE

• 왜 Public 에다가 두면 안되죠 ?–문법적으로 . 죄다 함수로 접근하게 하면 ()

같은거 써야하는지 안써야하는지 안헛갈려~–접근성에 대한 정교한 제어 가능–캡슐화 . –로그찍기도 편하고–그 멤버변수를 변경하기가 매우 힘들어진다

• 그렇다고 protected 는 된다는건 아니야 !–똑같어 ... 잘 생각해바 !

Page 31: Ec++ 3,4 summary

비멤버 비프렌드 Func

• 상식적으로–데이터와 그 데이터 이용하는 함수는 붙어있어야해 !

–정말 ... 그렇다고 생각하나요 ?

• 캡슐화를 한다는 것–바깥에서 볼 수 없다는 것–해당 기능을 바꿀 때 유연성이 증가

Page 32: Ec++ 3,4 summary

비멤버 비프렌드 Func

• 멤버 함수들은–내부 private 함수들 , 프렌드 함수들 등등 사용

가능해• 비멤버 비프렌드 함수들은–당연히 내부 private 함수 전혀 불가능해 !–어떻게 보면 더 캡슐화 된거 아니겠어 ?

• 그렇다고 다른 클래스의 멤버도 아닐 필요는 없어 !–그것은 딱히 캡슐화에 영향을 주지 않기 때문 .

Page 33: Ec++ 3,4 summary

비멤버 비프렌드 Func

• 그 비멤버 함수들을 어떻게 쉽게 관리하지 ?–해당 클래스와 같은 네임스페이스 안에 두는 것도

좋은 방법• 컴파일 의존성이 고민된다면–네임 스페이스만 공유하고–서로 다른 .h 파일에서 작업해도 되지 !

Page 34: Ec++ 3,4 summary

매개변수 , 타입 변환 해야하면그 함수는 100% 비멤버

class A { .... operator * (const A& rhs) } }...A a, b;A c = a * b; ---- OK

int iA d = a * i; ---- OKA e = i * a; ---- NO

Page 35: Ec++ 3,4 summary

매개변수 , 타입 변환 해야하면그 함수는 100% 비멤버

int i;A d = a * i; ---- OKA e = i * a; ---- NO

• 왜 d 는 되는 것일까 ?– 컴파일러님은 알고계신대 !

• A 가 와야하는데 int형이 온 경우 , 컴파일러가 알아채고 혹시 A 의 생성자 중에 int형으로 가능한 게 있으면 그것으로 암시적 타입 변환을 함 .

– 물론 명시적 생성자를 만들면 에러 ~!

Page 36: Ec++ 3,4 summary

매개변수 , 타입 변환 해야하면그 함수는 100% 비멤버

int i;A d = a * i; ---- OKA e = i * a; ---- NO

• 왜 d 는 되는 것일까 ?– 컴파일러님은 알고계신대 !

• A 가 와야하는데 int형이 온 경우 , 컴파일러가 알아채고 혹시 A 의 생성자 중에 int형으로 가능한 게 있으면 그것으로 암시적 타입 변환을 함 .

– 물론 명시적 생성자를 만들면 에러 ~!

Page 37: Ec++ 3,4 summary

매개변수 , 타입 변환 해야하면그 함수는 100% 비멤버

class A { .... operator * (const A& rhs) } }const A operator* ( const A& lhs, const A& rhs) {..};

int i;A d = a * i; ---- OKA e = i * a; ---- OK

• 비멤버 함수로 만들어 놓으면 가능하지롱 !– lhs, rhs 둘다 암시적 타입 변환 수행하도록 냅둬 !