Effective C++38 Effective C++ | 항목 27 캐스팅은 절약, 또 절약! 잊지 말자 항목 27 캐스팅은 최대한 절약하자 27.1 캐스팅 문법 ■ 27.1.1 캐스트 스타일 C 캐스트(구형 스타일 캐스트) (T) 표현식 T (표현식) C++ 캐스트(신형 스타일 캐스트) C++ 캐스트 설명 예시 const_cast(표현식) 객체의 상수성(constness) 혹은 휘발성(volatileness)을 없애는 용도로 사용한다. const → non-const static_cast(표현식) 암시적 변환을 진행하거나 타입을 거꾸로 변환하는 용도로 쓰인다. int → double void* → int* Parent* → Child* reinterpret_cast(표현식) 하부 수준 캐스팅을 위해 만들어진 연산자다. 구현 환경에 의존적이므로 이식성이 없다. int → char* dynamic_cast(표.. 2023. 3. 6. Effective C++ | 항목 26 변수 정의는 늦출 수 있는 데까지 늦추는 근성을 발휘하자 항목 26 변수 정의는 최대한 늦추자 26.1 변수 정의 ■ 26.1.1 변수 정의를 늦추는 방법 어떤 변수를 사용할 때가 되었을 때 비로소 변수를 정의한다. 변수를 정의할 때 초기화 인자로 바로 초기화한다. #include #include using namespace std; const int MinimumPasswordlength = 8; void encrypt(string& s); string encryptPassword(const string& password) { // string encrypted; 예외가 발생할 경우, 이 객체는 사용되지 않습니다. if (password.length() < MinimumPasswordlength) { throw logic_error("pw is too sho.. 2023. 3. 3. Effective C++ | 항목 24 타입 변환이 모든 매개 변수에 적용되어야 한다면 비멤버 함수를 선언하자 항목 24 타입 변환이 모든 매개 변수에 적용되어야 한다면 비멤버 함수를 선언하자 일반적으로 클래스에서 암시적 타입 변환을 지원하는 것은 잘못된 생각이다. 물론 숫자 타입은 예외인데, 예를 들어 정수에서 유리수의 암시적 변환은 허용해도 크게 이상하지 않다. 이 결정에 따라 Rational 클래스를 만들어보자. 24.1 멤버 함수의 암시적 타입 변환 Rational 클래스는 유리수를 나타내는 클래스이므로 덧셈, 곱셈 등 수치 연산을 기본으로 지원하려고 한다. 유리수의 곱셈은 Rational 클래스와 관련이 있으니 operator*를 Rational 클래스 안에 멤버 함수로 구현해보자. class Rational { public: Rational(int numerator = 0, int denominator.. 2022. 2. 15. Effective C++ | 항목 23 멤버 함수보다는 비멤버 비프렌드 함수와 더 가까워지자 항목 23 멤버 함수보다는 비멤버 비프렌드 함수와 더 가까워지자 23.1 멤버 함수 vs. 비멤버 비프렌드 함수 웹 브라우저를 나타내는 클래스가 있다고 가정해보자. 웹 브라우저로 다운로드한 파일을 저장한 캐시를 비우는 함수, 방문한 URL의 기록을 지우는 함수, 시스템이 갖고 있는 쿠키를 삭제하는 함수가 속해있다. 캡슐화 관점에서 봤을 때, 세 동작을 한꺼번에 호출하는 clearBrowserMember 멤버 함수와 clearBrowserNonMember 비멤버 함수 중 누가 더 좋은 걸까? class WebBrowser { public: void clearCache(); void clearHistory(); void clearCookies(); void clearBrowserMember(); }; voi.. 2022. 2. 15. Effective C++ | 항목 22 데이터 멤버가 선언될 곳을 private 영역임을 명심하자 항목 22 데이터 멤버가 선언될 곳은 private 영역임을 명심하자 이번 항목에서는 먼저 데이터 멤버가 왜 public이면 안 되는지 그 이유를 알아보고, 이 이야기가 protected 데이터 멤버에도 똑같이 적용되는 모습을 확인해 보도록 하자. 여기까지 끝나면 데이터 멤버는 반드시 private이어야 한다는 결론을 자연스럽게 볼 수 있을 것이다. 22.1 private가 아닌 데이터 멤버 ■ 22.1.1 public 데이터 멤버 public 데이터 멤버를 먼저 도마 위에 올려보자. 왜 데이터 멤버를 public으로 선언하면 안 될까? ① 문법적 일관성 우선 문법적 일관성에 어긋난다. 데이터 멤버가 private이라면, 사용자 쪽에서 어떤 객체에 접근할 수 있는 유일한 수단은 멤버 함수이므로 그 클래스.. 2022. 2. 11. Effective C++ | 항목 21 함수에서 객체를 반환할 경우에는 참조자를 반환하려고 하지 말자 항목 21 함수에서 객체를 반환할 경우에는 참조자를 반환하려고 하지 말자 값에 의한 전달에 숨겨진 효율 문제를 알아챈 프로그래머 중에는 코드에 멀쩡하게 들어있는 '값에 의한 전달'을 '참조에 의한 전달'로 모조리 바꾸어 실제로 있지도 않은 객체의 참조자를 넘기는 경우가 있다. 예를 들어, 어떤 유리수를 나타내는 클래스가 있다고 가정해보자. 이 클래스에는 두 유리수를 곱하는 멤버 함수가 선언되어 있다. class Rational { public: Rational(int numerator = 0, int denominator = 1); private: int n, d; /* 분자와 분모를 나타냅니다. */ friend const Rational operator*(const Rational& lhs, cons.. 2022. 2. 3. Effective C++ | 항목 20 값에 의한 전달보다는 상수 객체 참조자에 의한 전달이 대개 낫다 항목 20 값에 의한 전달보다 상수 객체 참조자에 의한 전달이 대개 낫다 20.1 값에 의한 전달: 객체 편 기본적으로 C++는 함수에 객체를 전달하거나 함수로부터 객체를 전달받을 때 값에 의한 전달(pass by value) 방식을 사용한다. 특별히 다른 방식을 지정하지 않는 한, 함수 매개 변수는 실제 인자의 사본을 통해 초기화되고 함수를 호출한 쪽은 그 함수가 반환한 값의 사본을 돌려받는다. 바로 이 사본을 만들어내는 행위 때문에 값에 의한 전달은 고비용의 연산이 된다. 아래 코드를 한번 보자. validateStudent 함수는 Student 인자를 값으로 전달받고 이 인자가 유효한지를 알려주는 bool 값을 반환한다. 이 함수가 호출될 때 과연 어떤 일이 일어날까?class Person {pub.. 2022. 2. 3. Effective C++ | 항목 19 클래스 설계는 타입 설계와 똑같이 취급하자 항목 19 클래스 설계는 타입 설계와 똑같이 취급하자 19.1 클래스 설계 고려사항 C++에서 새로운 클래스를 정의하는 것은 새로운 타입을 정의하는 것과 같다. 그렇기 때문에 클래스를 설계할 때는 마치 기본 타입을 설계하는 것처럼 많은 정성과 노력이 필요하다. 그럼 클래스를 효과적으로 설계하려면 어떤 것들을 고려해야 하는지 우선 파악해보자. 새로운 타입의 객체 생성 및 소멸은 어떻게 이루어져야 하는가? 이 부분에 따라서 클래스 생성자와 소멸자의 설계가 바뀐다. 객체 초기화는 객체 대입과 어떻게 달라야 하는가? (복사) 생성자와 복사 대입 연산자의 동작을 결정하는 요소이다. 초기화와 대입을 헷갈리지 않는 것이 중요하다. 새로운 타입으로 만든 객체가 값에 의해 전달되는 경우, 어떤 의미를 부여할 것인가? 어.. 2022. 2. 3. Effective C++ | 항목 18 인터페이스 설계는 제대로 쓰기엔 쉽게, 엉터리로 쓰기엔 어렵게 하자 2022. 2. 3. Effective C++ | 항목 17 new로 생성한 객체를 스마트 포인터에 저장하는 코드는 별도의 한 문장으로 만들자 항목 17 new로 생성한 객체를 스마트 포인터에 저장하는 코드는 별도의 한 문장으로 만들자 17.1 스마트 포인터를 인자로 받는 함수 처리 우선순위를 알려주는 함수가 하나 있고, 동적으로 할당한 Widget 객체를 우선순위에 따라 처리하는 함수가 하나 있다고 가정해보자. 이렇게 만들어진 processWidget 함수를 다음과 같이 호출하면 자원을 흘릴 가능성이 있다. int priority(); void processWidget(std::shared_ptr pw, int prior); processWidget(std::shared_ptr(new Widget()), priority()); /* 자원이 누출될 수 있습니다.*/ 컴파일러는 processWidget 호출 코드를 만들기 전에 우선 이 함수의 매.. 2022. 1. 25. Effective C++ | 항목 16 new와 delete를 사용할 때는 형태를 반드시 맞추자 항목 16 new와 delete를 사용할 때는 형태를 반드시 맞추자 16.1 객체와 객체 배열의 메모리 구조 new 표현식을 사용해서 어떤 객체를 동적 할당하면 두 가지 내부 동작이 진행된다. 일단 operator new 함수가 사용되어 메모리가 할당된다. 그다음, 할당된 메모리에 대해 한 개 이상의 생성자가 호출된다. 반면, delete 표현식을 사용하면 또 다른 두 가지 내부 동작이 진행되는데, 우선 할당된 메모리에 대해 한 개 이상의 소멸자가 호출되고, 그 후에 operator delete 함수가 사용되어 메모리가 해제된다. new로 힙에 만들어진 객체의 메모리 배치 구조(layout)는 객체 배열의 메모리 배치 구조와 다르다. 특히, 배열을 위해 만들어지는 힙 메모리에는 대개 배열의 원소 개수, .. 2022. 1. 25. Effective C++ | 항목 15 자원 관리 클래스에서 관리되는 자원은 외부에서 접근할 수 있도록 하자 항목 15 자원 관리 클래스에서 관리되는 자원은 외부에서 접근할 수 있도록 하자15.1 RAII 클래스의 변환 자원을 가지고 무엇인가 해야 할 때 자원 관리 클래스만 사용하면 좋겠지만, 이미 현장에서 쓰고 있는 수많은 API는 자원을 직접 참조하도록 만들어져 있어 자원 관리 객체의 보호벽을 넘어가서 자원을 직접 다루어야 할 일이 종종 있다. 항목 13에서 createInvestment 팩토리 함수를 호출한 결과, 그 포인터를 담기 위해 shared_ptr와 같은 스마트 포인터를 사용했었다. 이때 Investment 객체를 사용하는 daysHeld 함수를 다음과 같이 호출하고 싶을 수 있다.int daysHeld(const Investment* pi); /* 주식을 매수한 후 경과한 날 수 */std::s.. 2022. 1. 25. 이전 1 2 3 4 다음