목록C++ (43)
방프리
항목 21 : 함수에서 객체를 반환해야할 경우에 참조자를 반환하려고 들지 말자 일반적인 데이터 타입에서 사용되는 연산자(operator)는 미리 정의되어 있지만, 사용자가 정의한 클래스의 경우 연산자가 정해져 있지 않습니다. 이 덕분에 직접 operator 키워드를 통해 연산자를 재정의해서 사용하지요. 이 때 프로그래머들이 쉽게 실수할 수 있는 간단한 예를 살펴보며 하나씩 문제점을 짚어보겠습니다. (공통으로 사용되는 변수) Rational a(1, 2); // a = 1/2 Rational b(3, 5); // b = 3/5 Rational c = a * b; // c는 3/10이어야 합니다. 예제1) const Rational& operator* (const Rational& lhs, const Rat..
항목 20 : '값에 의한 전달'보다는 '상수객체 참조자에 의한 전달' 방식을 택하는 편이 대개 낫다. 보통 함수의 매개변수값으로 값을 전달할 때 이런 방식으로 많이 사용합니다. void CheckStudent( Student s ) { ... // 학생인지 아닌지 확인하는 소스 } 흔한 C++ 기본 서적에서도 많이 사용하고 있고, 실제로도 많이 사용하고 있습니다. 이번 항목은 이 흔한 코드를 좀 더 최적화를 할 수 있게 만드는데에 목적이 있습니다. 바로 값 복사입니다. 무슨 값 복사라는 사람들을 위해 매개변수로 전달되는 Student 타입의 변수 s가 호출되는 과정을 알아보겠습니다. int main(void) { Student m_cStudent; CheckStudent( m_cStudent ); } ..
항목 19 : 클래스 설계는 타입 설계와 똑같이 취급하자 좋은 클래스를 설계할 때 다음의 사항을 고려해보는 것이 좋습니다. (1) 새로 정의한 타입의 객체 생성 및 소멸은 어떻게 이루어져야 하는가? - 이 부분이 어떻게 되느냐에 따라 클래스 생성자 및 소멸자의 설계가 바뀝니다. 그 뿐 아니라 메모리 할당 함수를 직접 작성할 경우에는 이들 함수의 설계에도 영향을 미칩니다. (2) 객체 초기화는 객체 대입과 어떻게 달라야 하는가? - 각각 해당하는 함수의 호출이 다르기 때문에 초기화와 대입 간의 차이점에 대해 알고 있어야 합니다. (3) 새로운 타입으로 만든 객체가 값에 의해 전달되는 경우에 어떤 의미를 줄 것인가? - 복사 생성자를 유의하고 있으면 됩니다. (4) 새로운 타입이 가질 수 있는 적법한 값에 ..
항목 18 : 인터페이스 설계는 제대로 쓰기엔 쉽게, 엉터리로 쓰기엔 어렵게 하자 프로그래머도 사람입니다. 언제나 실수하기 마련이죠. 하지만 이 실수가 굉장히 큰 버그를 만들 수 도 있습니다. 예를 들어보겠습니다. class Date { public: Date(int month, int day, int year); }; Date d(30, 3, 1995); // 날짜와 월을 바꾸어서 초기화 만약 이렇게 잘못된 데이터가 들어갈 경우 그 결과는.... 여러분의 상상에 맡기겠습니다. 이러한 잘못된 코드를 최소한으로 줄여야 하기 때문에 맨 처음부터 인터페이스 설계를 탄탄하게 만들어야 합니다. struct Day { explicit Day (int d) : val(d) int val; }; struct Month..
항목 17 : new로 생성한 객체를 스마트 포인터에 저자하는 코드는 별도의 한 문장으로 만들자 하나의 예제 코드를 보고 시작하겠습니다. int priority(); void processWidget(std::tr1::shared_ptr pw, int priority); ... processWidget(new Widget, priority()); 자 간단한 코드입니다. 객체의 우선순위를 정하는 코드인데 priority() 함수를 통해 각 객체의 우선순위를 알아내고 processWidget을 통해 우선순위에 따라 처리를 하는 함수인 processWidget() 함수를 만들었습니다. 가만 보자 하니 processWidget() 함수에서 매개인자로 Widget 객체 포인터와 우선순위를 받는데 매개 인자를 동적..
항목 16: new 및 delete를 사용할 때는 형태를 반드시 맞추자 프로그래밍을 할 때 개발자는 한정적인 메모리 자원을 가지고 코딩을 하게 됩니다. 자원이 한정적이다 보니 메모리를 사용한다면? 다시 돌려놓기도 해야하죠. 이 과정을 C언어에서는 malloc, free로 이루어지고 C++에서는 new, delete를 통해 이루어집니다. 일방적으로 new만 계속 사용한다면? 진행은 되긴 됩니다만... 메모리 공간이 남아나질 않겠죠 ㅎㅎ 또 하나 반드시 알아야 할 것은 단일 객체의 생성일 때와 배열 객체의 생성일 때에 맞추어 new, delete도 다르게 해주어야 한다는 것입니다. 단일 객체일 때에는 delete, 배열 객체일 때에는 delete [] 를 꼭 사용해야 합니다. 만약 바꾸어서 하게 된다면 그에..
항목 15 : 자원 관리 클래스에서 관리되는 자원은 외부에서 접근할 수 있도록 하자. RAII방식으로 구현된 객체의 경우에 자원의 관리에 중점을 두었기 때문에 특성상 여러 군데에서 사용할 수 있어야 합니다. 또한 그 안에 있는 데이터도 접근이 가능해야 하죠. 그렇다 보니 RAII 클래스의 객체를 그 객체가 감싸고 있는 실제 자원으로 변환할 방법이 필요해집니다. 변환하는 방법은 보편적으로 명시적 변환과 암시적 변환 두 가지로 나뉘게 됩니다. 명시적 변환의 경우 get() 함수를 통해 자원의 상태를 반환하며, set() 함수를 통해 데이터의 조작을 이루어지게 합니다. 즉, 특정 함수를 통해 자원의 참조자를 얻고 얻은 데이터를 통해 조작이 이루어지게 하는 것이죠. 암시적 호출방식은 operator T()를 이..
항목 14 : 자원 관리 클래스의 복사 동작에 대해 진지하게 고찰하자 모든 자원은 힙에서 생성되지 않습니다. 그렇기 때문에 앞의 13항목에서 배운 auto_ptr 이나 tr::shared_ptr의 경우 사용할 수 없다는 큰 제약이 생겨버립니다. 그래서 RAII 객체가 복사가 되거나 관리를 할 때 어떤 조건을 충족해야하는지 알아보겠습니다. (1) 복사를 금지합니다. - RAII 객체가 복사되도록 놔두는 것은 말이 안됩니다. 특히 뮤텍스처럼 쓰레드의 동기화를 일으키는 객체의 경우 사본이 있는다는건 더더욱 말이 안됩니다. 이걸 방지하는 방법으로는 복사 함수를 private로 선언해 복사를 막는 방법이 있습니다. (2) 관리하고 있는 자원에 대해 참조 카운팅을 수행합니다. - 객체가 복사될 경우 사본을 생성하는..