이펙티브 c++ 789 공부

14
effective c++ 템플릿, new delete

Upload: quxn6

Post on 12-Jul-2015

198 views

Category:

Software


8 download

TRANSCRIPT

effective c++ 템플릿, new delete

Template

명시적 인터페이스

: 클래스에서는 그 인터페이스의 소스 코드를 보면 이것이 어떤 형태인지 확인할 수 있다.

암시적 인터페이스

: 템플릿은 그 템플릿이 구현된 모습을 보고 어떤 인터페이스가 필요한지를 유추할 수 있다. 아래 같은 템

플릿이 있다면 템플릿화 될 T는 operator >, != size()등이 정의되어있어야 함을 알 수 있음.

template<typename T>

void doProcessing(T& w) {

if (w.size() > 10 && w != someNastyWidget) { 불라불라}

}

But, 암시적으로

컴파일 타임 다형성

: 템플릿을 인스턴스화 하는 과정에서 T의 타입이 결정된다. (어떤 매개변수가 들어가느냐에 따라 호출이

달라짐)

런타입 다형성

: virtual keywork같은거..

암시적 인터페이스와 컴파일 타임 다형성

템플릿 선언문은 둘이 완전히 동일함

template<class T> class Widget;

template<typename T> class Widget;

의존 이름(dependent name)

template<typename C>

void print2nd( const C& container) {

if (container.size() >=2)

C::const_iterator iter(container.begin()); // C에 따라 바뀌는 의존이름

int value = *iter // 여기서 value는 비의존 이름(non-dependent name)

의존 이름은 동일한 클래스(C)가 있다면 정상동작 하지 않을 수 있다. 따라서 앞에 typename을 붙여주

면 문제 해결(typename C::const_iterator iter(~~);)

** typedef를 할 때도 typename 키워드를 포함해서 하면됨

typedef typename C::const_iterator iter(~~);

typename의 두 가지 의미

완전 템플릿 특수화

템플릿이 클래스 A를 상속받은 클래스 B가 A의 함수를 사용한다면 컴파일러가 이 클래스 A가 어디서 파

생된 것인지를 찾을 수 없어( T가 뭐인지 정확히 몰라서 ) 에러가 발생한다.

template <typename T>

class A { public : void sendClear();}

class B : public A<T> {

void func() { sendClear(); } --- 에러발생

}

이는 완전 특수화된 템플릿을 위해 기본 클래스 함수에 대한 호출을 제한하기 때문이다. 아래와 같이 <>

만 붙이고 있는 놈들이 완전 템플릿 특수화 된 것이다.

template<>

class A<Tem> { ~~ }

따라서 기본 클래스에 접근할 때는 아래 세 가지 방법을 사용한다.

this->sendClear();

using A<T>::sendclear;

A<T>::sendClear() - 이 방법은 가상함수 바인딩이 무시되기 때문에 비추

template으로 만든 기본클래스 안의 이름에 접근하는 방법

코드 비대화

템플릿으로 여러 클래스를 만들다보면 소스 코드는 날씬하나 동일한 내용을 가진 클래스가 여럿 생길 수

있다.

따라서 매개변수(template<T> 에서 T) 에 독립적인 코드는 템플릿에서 분리시켜야 한다.

방법은 base template class를 만들어 독립적인 함수를 넣고 이를 상속받아 자식클래스에서 매개변수를

사용하는 부분을 작성하면 됨

자식 클래스 부모 클래스로 데이터 넘기기

부모 클래스에서 멤버 변수로 데이터에 대한 포인터를 갖고, 이를 생성자에서 초기화

자식 클래스에서 멤버 변수로 데이터를 갖고, 생성자에서 위에서 만든 부모 클래스의 생성자를 호출,

이 때 멤버 변수의 주소를 넘김

자식 클래스의 크기를 줄이기 위해서

혹은 자식 클래스에서도 데이터에 대한 포인터만 갖고 데이터는 힙에 생성하는 방법도 있음

매개변수에 독립적인 코드는 템플릿에서 분리 시키자

멤버함수 템플릿

일반 포인터는 부모 클래스 포인터로 자식 클래스를 가리킬 수 있다. 이는 암시적 변환을 지원하기 때문인

데, shared_ptr<>같은 템플릿에서는 이를 지원하지 않는다. 이를 해결하기 위해 멤버함수 템플릿을 사

용한다.

일반화 복사 생성자

template<typename T>

class SmartPtr{

public :

template<typename U>

SmartPtr(const SmartPtr<U>& other)

};

이렇게 하면 smartPtr<T> 객체가 smartPtr<U> 로부터 생성될 수 있다는 뜻. 이 생성자를가 일반화 복

사 생성자

호환되는 모든 타입을 받아들이는 데는 멤버 함수 템플릿을사용

암시적 형변환

클래스 내 멤버 함수는 암시적 형변환이 안됨. 템플릿 인자 추론 과정에서 암시적 형 변환을 고려하지 않

기 때문.

operator* 을 이용해서 Rational<int> * 2 를 하게 되면 2를 Rational<int>(2)로 형변환 못해서 컴파

일 불가함

따라서 operator* 를 friend함수로 만들면 클래스 안에 있더라도 비멤버 함수가 되고 암시적 형변환이 가

능해짐

But, 클래스 내부에서 정의도 해주어야 함

friend 함수가 inline 함수가 되는 것 막기

이대로 두면 operator*의 정의가 클래스 내부에 있기 때문에 암시적으로 inline함수로 변환시킴. 이 함수

가 너무 클 경우 실제 operator* 기능을 수행하는 함수를 클래스 외부에 따로 만들고 friend함수에서는

그 함수를 호출만 하는 방식으로 사용할 수 있음

타입 변환이 바람직할 때는 비멤버 함수를 클래스 템플릿 안에 정의

new delete

시스템에서 제공하는 new와 delete도 훌륭하다.

잘 만든 상용 메모리 관리자나 open source도 있다.

그럼에도 불구하고 직접 만들겠다면 목적을 명확히 해야 한다.

직접 만드는 경우는 아래와 같다.

잘못된 힙 사용을 탐지하기 위해

동적 할당 메모리의 실제 사용에 관한 통계 정보를 수집하기 위해

할당 및 해제 속력을 높이기 위해

기본 메모리 관리자의 공간 오버헤드를 줄이기 위해

적당히 타협한 기본 할당자의 바이트 정렬동작을 보장하기 위해

임의의 관계를 맺고 있는 객체들을 한 군데에 나란히 모아 놓기 위해

그때그때 원하는 동작을 수행하도록 하기 위해

언제 사용자 정의 new 와 delete를 만들어야 하는가?

반환값이 제대로 있어야 한다.

가용 메모리가 부족할 경우에는 new 처리자 함수를 호출해야 한다.

크기가 없는 메모리 요청에 대한 대비책을 갖춰두어야 한다.

기본 형태의 new가 가려지지 않게 한다.

기본적으로 메모리를 할당하기 위해 무한 루프를 도는 구조로 되어있다.

new 와 delete 작성 시 관례

위치 지정 new

new(void std::size_t, *pMemory) 식으로 크기 뿐 아니라 위치까지 직접 받아서 그 곳에 만드는 new

이러한 new가 있는 경우에 delete가 무엇이 호출되어야 하는지 헷갈릴 수 있으므로 컴파일러는 아무

delete도 호출하지 않는다. 따라서 짝이 되는 위치지정 버전의 delete도 만들어야 함.

**표준 버전을 가리지 않게 조심할 것!!

위치 지정 new를 작성한다면 위치 지정 delete도 짝으로 만들자

그 밖의 이야기들

컴파일러 경고를 지나치지 말자

최고 경고 수준에서도 컴파일 되는 코드를 만들자.

** 하지만 너무 믿지는 말자. 컴파일러마다 다를 수 있으니

TR1을 비롯한 표준 라이브러리 구성요소에 능숙해지자.

대부분은 이미 C++11 에서 정식으로 채택된 기능 들이다.

스마트 포인터

function : 함수 호출성 객체(call back함수등)을 만들 때 유용함

void callbackfunc(std::function<std::string (int)> func); std::string을 반환값으로 괄호에 있

는 값들을 매개변수로 사용하는 호출성 객체들을 넣을 수 있음

bind

hash table : set, multi_set, map, multi_map 등등

정규표현식

투플

std::array : 기본 어레이와 동일하지만 오버런 언더런으로부터 지켜주는놈

난수발생, math 등등

boost.org에는 막강한 라이브러리들이 많이 있다. 잘 활용하자

그 밖의 이야기들