항목 31 : 파일 사이의 컴파일 의존성을 최대로 줄이자 객체 참조자 및 포인터로 충분한 경우에는 객체를 직접 쓰지 않습니다. 어떤 타입에 대한 참조자 및 포인터를 정의할 대는 그 타입의 선언부만 필요합니다. 반면, 어떤 타입의 객체를 정의할 때는 그 타입의 정의가 준비되어 있어야 합니다. 할 수 있으면 클래스 정의 대신 클래스 선언에 최대한 의존하도록 만듭니다. 어떤 클래스를 사용하는 함수를 선언할 때는 그 클래스의 정의를 가져오지 않아도 됩니다. 심지어 그 클래스 객체를 값으로 전달하거나 반환하더라도 클래스 정의가 필요없습니다. 선언부와 정의부에 대해 별도의 헤더 파일을 제공합니다. "클래스를 둘로 쪼개자"라는 지침을 제대로 쓸 수 있도록 하려면 헤더 파일이 짝으로 있어야 합니다. 하나는 선언부를 위..
항목 30 : 인라인 함수는 미주알고주알 따져서 이해해 두자 인라인 함수를 사용하면 컴파일러가 함수 본문에 대해 문맥별 최적화를 걸기가 용이해집니다. 실제로 대부분의 컴파일러는 '아웃라인' 함수 호출에 대해 이런 최적화를 적용하지 않습니다. 인라인 함수 사용시 코드의 크기가 커질수 있으며 이는 성능의 걸림돌이 될 수도 있습니다. 하지만 본문 길이가 굉장히 짧은 인라인 함수를 사용할 경우 함수 본문에 대해 만들어지는 코드의 크기가 함수 호출문에 대해 만들어지는 코드보다 작아질 수도 있습니다. 인라인 함수는 대체적으로 헤더 파일에 들어 있어야 하는게 맞습니다. 대부분의 빌드 환경에서 인라인을 컴파일 도중에 수행하기 때문입니다. 인라인 함수 호출을 그 함수의 본문으로 바꿔치기하려면 컴파일러가 그 함수가 어떤 ..
항목 29 : 예외 안전성이 확보되는 그날 위해 싸우고 또 싸우자! 예외 안전성을 확보하려면 두 가지의 요구사항을 맞추어야 합니다. 1. 자원이 새도록 만들지 않습니다. 2. 자료구조가 더럽혀지는 것을 허용하지 않습니다. 예외 안전성을 갖춘 함수는 세 가지 보장중 하나를 제공합니다 1. 기본적인 보장 : 함수 동작 중에 예외가 발생하면, 실행 중인 프로그램에 관련된 모든 것들을 유효한 상태로 유지하겠 다는 보장입니다. 어떤 객체나 자료구조도 더럽혀지지 않으며, 모든 객체의 상태는 내부적으로 일관성을 유지하고 있습니다(즉, 모든 클래스 불변속성이 만족된 상태입니다). 2. 강력한 보장 : 함수 동작 중에 예외가 발생하면, 프로그램의 상태를 절대로 변경하지 않겠다는 보장입니다. 이런 함수를 호출하는 것은 원..
항목 28 : 내부에서 사용하는 객체에 대한 '핸들'을 반환하는 코드는 되도록 피하자 핸들을 반환하는 함수는 문제를 발생시킬수 있습니다. 예를 들면, 무효참조 핸들입니다. 핸들이 있기는 하지만 그 핸들을 따라갔을 때 실제 객체의 데이터가 없는 것이죠. 객체의 내부에 대한 핸들을 반환하는 함수는 위험합니다. 이유는 간단합니다. 바깥으로 떨어져 나간 핸들이 그 핸들이 참조하는 객체보다 더 오래 살 위험이 있기 때문입니다. 꼭 잊지 말아야 할 것! 어떤 객체의 내부요소에 대한 핸들(참조자, 포인터, 반복자)을 반환하는 것은 되도록 피하세요. 캡슐화 정도를 높이고, 상수 멤버 함수가 객체의 상수성을 유지한 채로 동작할 수 있도록 하며, 무효참조 핸들이 생기는 경우를 최소화할 수 있습니다.
항목 27 : 캐스팅은 절약, 또 절약! 잊지 말자 이번 항목에서는 캐스팅에 대해 소개해보도록 하겠습니다. 일단 캐스팅 문법 정리부터 시작하도록 하겠습니다. 똑같은 캐스트인데 쓰는 방법이 세 가지나 있습니다. 우선 C 스타일의 캐스트입니다. (T) 표현식 // 표현식 부분을 T 타입으로 캐스팅합니다. 다음은 함수 방식 캐스트입니다. T (표현식) // 표현식 부분을 T 타입으로 캐스팅합니다. 이 두 형태를 통틀어 '구형 스타일의 캐스트'라고 부르겠습니다. C++는 네 가지로 이루어진 새로운 형태의 캐스트 연산자를 독자적으로 제공합니다(신형 스타일의 캐스트 혹은 C++ 스타일의 캐스트 라고 부르죠) const_cast(표현식) dynamic_cast(표현식) reinterpret_cast(표현식) stat..
항목 26 : 변수 정의는 늦출 수 있는 데까지 늦추는 근성을 발휘하자 생성자 혹은 소멸자를 끌고 다니는 타입으로 변수를 정의하면 반드시 물게 되는 비용이 두 개 있습니다. 하나는 프로그램 제어 흐름이 변수의 정의에 닿을 때 생성자가 호출되는 비용이고, 또 하나는 그 변수가 유효범위를 벗어날 때 소멸자가 호출되는 비용입니다. 변수가 정의됐으나 사용되지 않은 경우에도 비용이 부과됩니다. 밑에 예제가 있습니다. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 // 이 함수는 "encrypted" 변수를 너무 일찍 정의해 버립니다. std::string encryptPassword(const std::string& password) { using namespace std; string e..