본문 바로가기

Effective C++/5. 구현

(6)
항목31: 파일 사이의 컴파일 의존성을 최대한 줄이자 클래스 하나가 맘에 안들어서 소스 코드 한 줄을 수정했다. 인터페이스도 아니고 구현부인데다가 외부에 노출도 안되는 코드이다. 컴파일하는데 몇 초 안걸릴 거 같다. 빌드를 눌렀다. 느낌이 이상하다. 한참을 기다려도 빌드가 안끝난다. 엄; 문제의 핵심 : C++는 인터페이스와 구현의 분리가 깔끔하게 안되있다. 정확히 말하면 이 둘을 분리하는 문법적 장치같은것이 없음 => 사용자가 알아서 분리해야함 C++의 클래스 정의(class definition)은 클래스 인터페이스만 지정하는 것이 아니라 구현까지 상당히 많이 지정하고 있다. 위 코드만 가지고는 Person 클래스가 절대 컴파일되지 않겠다. => string, Date, Address가 어떻게 정의됬는지 모르기 때문이다. => 이들의 정의를 어디선가 가져..
항목 30: 인라인 함수는 미주알고주알 따져서 이해해 두자. 인라인함수 = 함수 호출문 -> 함수 본문으로 바꿔치기 인라인 함수의 장점 인라인 함수 => 함수처럼 보이고, 함수처럼 동작하고, 매크로보다 훨씬 안전하고(항목 2 참조), 함수 호출 시 오버헤드도 걱정할 필요 없고 + 컴파일러 최적화는 함수 호출이 없 코드가 연속적으로 이어지는 구간에 보통 적용되도록 설계되었기 때문에, 인라인 함수를 사용하면 컴파일러가 함수 본문에 대해 문맥별(context-specific) 최적화를 걸기가 쉽다. 아웃라인 함수엔 적용X 인라인 함수의 단점 목적 코드의 크기가 커진다!!! => 제한된 메모리 환경에서는 코드가 메모리에 다 올라가지 못할 수도 있고, 가상 메모리 환경이더라도 페이징 횟수가 늘어나고, 명령어 캐시 적중률이 떨어질 가능성이 높다. [운영체제 OS] 메모리 관..
항목 29: 예외 안전성이 확보되는 그날 위해 싸우고 또 싸우자! 예외 안정성에 이보다 나쁜 함수가 없다. 예외 안정성을 가진 함수를 만들려면... 자원이 새도록 만들지 않는다. 위 코드는 만약 new 에서 예외를 던지면 unlock()이 실행되지 않기 때문에 뮤텍스가 계속 lock 된 상태로 남게 된다. 자료구조가 더럽혀지는 것 하용하지 않는다. 위 코드는 만약 new 에서 예외를 던지면 bgImage가 가르키는 객체는 이미 사라진 후이고, 새 그림이 깔리지도 않았는데 imageChanges는 1 증가하고, 여튼 문제가 많다. ====================================================================== 자원 누출 문제부터 해결해보자. => 자원 관리 객체를 사용하면 됨 항목 13을 참고하자. 일단 자원(mutex)가 ..
항목 28: 내부에서 사용하는 객체에 대한 '핸들'을 반환하는 코드는 되도록 피하자. 사각형(Rectangle)을 사용하는 응용프로그램을 만드는 중이다.. 사각형은 좌측상단 꼭짓점과 우측하단 꼭짓점으로 나타낼 수 있다. 그리고 메모리 부담을 줄여야 한다. => 사각형의 영역을 정의하는 꼭짓점을 Rectangle 자체에 넣기 보다, 꼭짓점을 별도의 클래스(RecData)에 넣은 후 Rectangle은 이 구조체를 가르키도록 했다. 사용자가 꼭짓점 정보가 필요할 때가 있으니 꼭짓점 정보를 반환하는 upperLeft()와 lowerRight()를 선언했는데, const인데 Point&(꼭짓점에 대한 핸들)를 반환했다. => 함수 자체에선 내부 정보를 안건드니까 const로 해도 에러가 안뜨지만, 반환된 Point 핸들은 아무 제약이 없으므로, 실질적으로 데이터가 바뀔 수 있다. 즉 이런 코드가..
항목 27: 캐스팅은 절약, 또 절약! 잊지 말자 "어떤 일이 있어도 type error가 생기지 않도록 보장한다" => C++의 동작 규칙이다. 즉, 이론적으로는 컴파일만 잘 되면, 그 이후엔 어떤 객체에 대해서도 불완전한 연산, 말도 안되는 연산 등을 수행하지 않는다는 것이다. 하지만!!! cast 시스템 때문에, 이런 보장이 깨질 수 도 있다.. C++에서 cast는 항상 조심 또 조심 해야한다. 일단 C++에서 제공하는 casting 문법부터 정리하면 (T) expression T(expression) 여기까지가 구형 캐스트 이다. const_cast(expression) dynamic_cast(expression) reinterpret_cast(expression) static_cast(expression) 이 4개는 C++에서 독자적으로 제공..
항목 26: 변수 정의는 늦출 수 있는 데까지 늦추는 근성을 발휘하자 사용자 정의 타입의 변수를 정의하면(즉 메모리를 할당하면), 반드시 따라오는 비용이 있다. -> 생성자 호출 비용, 소멸자 호출 비용 만약 변수를 만들고 사용하지 않아도 들어가는 필수비용이다. 변수를 만들고 사용 안할 경우가 있나? 싶은데 이런 경우가 있다. 변수 정의를 늦게 하면(진짜 필요해질 떄까지 정의를 미루면) 생성자와 소멸자 비용을 아낄 수 있다. 위 코드의 흠을 잡으라면, encrypted가 기본생성자를 호출한다는 것이다. 어짜피 나중에 값이 들어갈껀데, 이땐 대입으로 넣을 것이다. 초기화 vs 대입 이면 초기화가 더 좋음(항목 4 참고) 비밀번호를 암호화하는 함수가 하나 있다고 가정하고 이렇게 쓰는 것 보다 이렇게 쓰는 것이 훨씬 좋다. 즉 미룰 수 있을 때 까지 미루라는 말은 어떤 변수를 ..