C++테크닉 15

[Effective C++]항목 53~55: 기타

항목 53 : 컴파일러 경고를 지나치지 말자 프로그래밍을 하다보면 컴파일은 정상적으로 되지만 컴파일러 경고가 나오는 경우가 있다. 이때 이러한 경고는 무시하지말고 무엇을 말하고 있는지를 살펴보아야한다. 대부분의 컴파일러 경고는 문법상 문제는 없지만 코드의 맥락이 직관적인 부분과 다르게 동작할 때 발생한다. 예를 들어 부모에서 f라는 가상 함수를 const로 선언하고 자식이 비 const f함수를 작성하였다면 일부 컴파일러에서 자식의 f가 부모의 f를 가린다고 경고를 띄운다. 실제로 자식의 f가 부모의 f를 가리기에 자식 인스턴스는 부모 포인터와 자신의 포인터에 담겨있을때 서로 다른 f를 호출한다. 객체지향의 기본 동작에서 벗어난 것이다. 이런식으로 겉으로 드러나는 직관적인 부분과 실제 동작이 다른 부분을..

[Effective C++]항목 49~52: new와 delete

항목 49 : new 처리자 new처리자는 new로 메모리 할당에 실패했을때 메모리 확보를 위해 시도되는 함수이다. 표준 new의 경우 다음과 같이 처리된다. 1. 매개변수로 할당할 바이트 사이즈를 받는다. 2. 바이트 사이즈가 0이면 1로 바꾼다 3. while(true) 4. malloc으로 사이즈만큼 할당시도 5. 성공시 할당된 포인트 리턴 6. 실패시 설정된 new 처리자 호출(new 처리자가 null 함수 포인터로 설정되있다면 throw bad_alloc) 7. 예외가 던져지거나 성공할때까지 반복 프로그래머는 의 set_new_handle에 void (void) 함수 포인터를 넣어 new 처리자를 자신이 만든 것으로 설정할 수 있다. 이때 리턴값은 기존 함수 포인터이다. new 처리자는 다음중 ..

[Effective C++]항목 45~48: 템플릿 2

항목 45 : 멤버 함수 템플릿클래스 템플릿 안에는 별개의 템플릿을 가지는 멤버 함수를 만들 수  있다. template class c{ public: tempalte void fff(U a);}이렇게 하면 특정 클래스 템플릿 인스턴스에서 특정 타입의 fff를 호출할때마다 해당 멤버함수가 생성되며 호출된다. 이러한 멤버 함수 템플릿의 대표적인 사용예시는 일반화 복사 생성자이다.스마트 포인터 템플릿을 만든다고 해보자. 만약 평범하게 자신에 대한 복사 생성자 만든다면 자식 타입에 대한 스마트 포인터를 부모 타입에 대한 스마트 포인터에 복사 생성할 수 가 없다. 이를 구현하기 위해선 멤버 함수 템플릿으로 smartPoint를 매개변수로 받는 복사 생성자를 만들면 된다. 그후 매개..

[Effective C++]항목 41~44: 템플릿 1

항목 41 : 템플릿의 특성 템플릿은 다음과 같은 두가지의 추가적인 특성을 가지는 문법이다. 암시적 인터페이스 기존 문법에서는 특정 타입의 연산자나 멤버에 접근할 때 명시적으로 특정 타입의 인터페이스에 접근한다. 하지만 템플릿에서는 타입 매개변수의 객체에 대해 암시적 인터페이스를 통해 멤버에 접근한다. 타입 매개변수에 입력되는 타입들은 해당 템플릿에서 상용한 암시적 인터페이스들에 대해 모두 유효해야한다. 그렇지 않다면 템플릿 인스턴스를 만드는 컴파일 타임에 에러가 발생한다. 컴파일 타임 다형성 기존 문법에서는 다형성을 사용할 때 런타임에 해당 레퍼런스에 들어있는 실제 객체가 무엇인지 인식하여 호출될 함수가 정해졌었다. 그에 비해 템플릿의 타입 매개변수를 활용한 다형성은 템플릿 인스턴스를 만들 때 해당 타..

[Effective C++]항목 38~40: 객체 지향 설계 3

항목 38 : 객체 합성 객체 합성은 그냥 한 클래스가 다른 클래스를 멤버로 가지는 것을 의미한다. 이는 개념적으로 보통 두가지 중 하나의 의미를 가진다. has-a 밖 클래스가 안 클래스를 개념적으로 소유한 경우이다. person 클래스가 string name, Address adress등의 멤버를 가진 경우에 해당된다. 보통 클래스가 현실의 객체를 나타낼때 나타난다.. is-implemented-in-terms-of 밖 클래스가 안 클래스를 구현에 활용하는 경우이다. 하나의 부품으로 사용했다고 봐도 무방할 듯 하다. stack 클래스가 내부적으로 list 객체를 멤버로 가지고 있고 이를 이용하여 구현된 경우 등이 해당된다. 보통 시스템 구현을 위한 인공물 클래스에서 나타난다. 항목 39 : priva..

[Effective C++]항목 35~37: 객체 지향 설계 2

항목 35 : 가상함수 대체제들 가상 함수는 재정의 가능한 함수를 상속하기 위해 사용한다. 이때 가상함수대신 여기에 쓸 수 있는 기법들을 살펴보자. 비가상 인터페이스 이 기법은 재정의가 필요한 부분을 private나 protected 가상 함수로 선언하고 이를 중간에 호출하여 사용하는 public 인터페이스 비가상 함수를 구현하여 제공하는 방법이다. 이렇게 하면 자식은 상속받은 private또는 protected 비가상 함수를 재정의할 것이고 사용자들은 재정의된 private함수를 사용하는 public 비가상 함수를 호출하여 사용할 것이다. 참고로 private도 자식에서 재정의는 가능하다.(호출은 불가능) 이 방식의 장점은 재정의 구현 부분 앞뒤로 기본 처리를 넣어줄 수 있다는 점이 있다. 함수 포인터..

[Effective C++]항목 32~34: 객체 지향 설계 1

항목 32 : public 상속은 is-a 관계이다. public 상속은 is-a관계를 의미한다. c가 p를 상속받는다면 c는 p이다. 하지만 p는 c가 아니다. 기본적인 상속 개념이다.객체 지향 설계에서 상속 계층구조를 설계할 때는 이러한 부분을 잘 고려해야한다. 대표적인 예시로 bird라는 클래스가 있다고하자. 이때 bird에 fly라는 함수를 넣어야할까? 만약 펭귄이 bird를 상속받는다면 이는 문제가 될 수 있다. 펭귄은 날 수 없기 때문이다. 이를 위한 해결책은 bird아래에 canflybird라는 계층을 하나더 두는 방법이 대표적이다. 아니면 bird에 fly를 가상함수로 넣고 펭귄에서 오버라이드하여 에러를 띄우는 등의 특수한 처리를 해주면 될 것이다. 어떤게 더 나은 설계인지는 자신이 만들고..

[Effective C++]항목 29~31: 구현 2

항목 29 : 예외 안정성 예외 안전성이란 어떤 함수가 자신이 실행 중 발생한 예외를 어떻게 처리하는지에 대한 안정성 수준을 이야기한다.예외 안정성에서 신경써야하는 부분은 크게 두가지이다.1. 동적할당, 뮤텍스등의 할당한 자원 해제2. 로직 무결성 유지1번째의 경우 스마트포인터, 소멸자 기반 뮤텍스등으로 쉽게 해결가능하다. 하지만 2번의 경우 스스로 로직을 잘짜야하기에 신경쓸 것이 많다.우선 예외 안정성은 다음 3가지 수준을 가진다. 기본적인 보장함수 실행 중 중간에 예외 발생시에도 무결성을 해치지않는다. 즉 정상적인 상태를 유지한다.강력한 보장함수 실행 중 중간에 예외 발생시 함수 호출전의 상태를 보존해준다. 즉 실행성공, 실행 실패 두가지 상태만 존재하며 원자성을 보장해준다.예외불가 보장함수가 밖으로..

[Effective C++]항목 26~28: 구현 1

항목 26 : 변수 생성 타이밍은 신중히하자.클래스 객체 같은 경우 변수의 생성은 기본적으로 큰 비용을 따른다. 생성자의 호출 및 이후 소멸자의 호출을 하기 때문이다. 만약 어떤 함수에서 변수를 생성할 땐 필요한 순간까지 기다렸다가 필요한 순간에 생성하는 것이 좋다. 괜히 함수 호출 초반에 변수를 생성하면 예외 처리등에 의해 해당 변수를 사용하기전에 함수가 리턴되어 끝나버릴 수도 있기 때문이다. 이경우 변수는 사용되지도 않았으면서 생성자 및 소멸자에 대한 비용을 유발하기에 성능에 좋지않다. 디자인의 측면에서도 변수를 실제 사용전 생성하면 생성하는 변수의 용도를 알기 쉬워 좋다.추가로 변수 생성 후 대입보다는 해당 초기화 값으로 바로 생성할 수 있으면 그렇게 하는 것이 당연히 더 성능이 좋다.마지막으로 반..

[Effective C++]항목 23~25 : 클래스에 대한 비멤버 함수

항목 23 : 비멤버 비프렌드로 제공가능한 함수는 그렇게 만들자 public 함수 a,b,c를 가지고 있는 클래스 widget이 있다고 하자. 이때 클래스에 d라는 함수를 추가한다고 하자. d는 자체적인 private접근없이 a,b,c를 차례로 호출하는 기능만을 가지는 함수이다. 즉 유틸함수에 가까운 함수이다. 이때 d라는 함수를 멤버 함수로 만들 수도 있겠지만 그보단 외부에서 호출하는 비멤버 비프렌드 util함수로 선언하는 것이 좋다. d(widget& w)로 위젯을 받아 위젯의 a,b,c를 순서대로 호출하면 된다. 마치 절차지향처럼 말이다. 모순적이게도 이러한 함수 구현 방식이 클래스의 캡슐화를 향상 시킨다. 이게 무슨 소리일까? 역할군이 확실히 나누어진 객체지향 작업에서 클래스 제작자가 클래스의 내..