본문 바로가기

카테고리124

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.
전문가를 위한 C++ | Chapter 10 상속 활용하기(상) 10.1 상속을 이용한 클래스 구현 현실에 존재하는 대상은 대체로 계층 구조에 속한다. 프로그래밍을 할 때도 클래스를 수정하거나 다른 클래스를 바탕으로 새 클래스를 정의할 때 이러한 관계를 분명히 볼 수 있다. C++는 진정한 is-a 관계를 정의하는 기능을 기본으로 제공한다. 10.1.1 클래스 상속하기 C++에서 클래스를 정의할 때 컴파일러에 클래스를 상속(inherit), 파생(derive), 확장(extend)한다고 선언할 수 있다. 이때 원본 클래스를 부모 클래스(베이스 클래스(base class) 또는 슈퍼 클래스(super-class))라고 부른다. 그러면 원본 클래스를 확장한 자식 클래스(파생 클래스(derived class) 또는 서브 클래스(sub-class))는 부모 클래스와 다른 부.. 2022. 1. 30.
전문가를 위한 C++ | Chapter 07 메모리 관리(하) 7.3 로우 레벨 메모리 연산 특정 애플리케이션이나 레거시 코드에서 로우 레벨 메모리를 다뤄야 할 때가 있다. 메모리를 저수준으로 관리하는 테크닉을 알아두면 여러모로 도움이 된다. 7.3.1 포인터 연산 C++ 컴파일러는 포인터 연산을 수행할 때 포인터에 선언된 타입을 이용한다. 예를 들어 다음과 같이 int 타입의 힙 배열을 선언한 경우를 살펴보자. 포인터 연산의 강점은 myArray + 2와 같이 표현식으로 포인터를 표현하고, 이를 이용해서 더 작은 정수 배열을 표현할 수 있다는 데 있다. int* myArray = new int[8]; myArray[2] = 10; *(myArray + 2) = 10; /* 포인터 연산으로 역참조합니다. */ 다음과 같이 와이드 문자열(wide string)을 인수.. 2022. 1. 29.
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.
Effective C++ | 항목 14 자원 관리 클래스의 복사 동작을 고찰하자 항목 14 자원 관리 클래스의 복사 동작을 고찰하자14.1 RAII 클래스의 복사 동작 자원 관리 클래스를 스스로 만들어야 하는 경우가 있다. 예를 들어, Mutex 타입의 뮤텍스 객체로 C API를 사용하고 있다고 가정해보자. RAII 법칙에 따라 이전에 걸어 놓은 뮤텍스 잠금을 풀어주는 Lock 클래스는 다음과 같이 정의할 수 있다.void lock(Mutex* pm); /* pm이 가리키는 뮤텍스의 잠금을 설정하는 C API 함수입니다. */void unlock(Mutex* pm); /* pm이 가리키는 뮤텍스의 잠금을 해제하는 C API 함수입니다. */class Lock {public: explicit Lock(Mutex* pm) : mutexPtr(pm) { lock(mutexPtr); /*.. 2022. 1. 24.
Effective C++ | 항목 13 자원은 객체로 관리하자 항목 13 자원은 객체로 관리하자13.1 자원 관리 클래스 투자를 모델링해주는 클래스 라이브러리에 Investment라는 최상위 클래스가 있고 이것을 기본으로 다양한 투자 클래스가 파생되어 있다고 가정해보자. 이 라이브러리는 Investment에서 파생된 클래스의 객체를 사용자가 얻어내는 용도로 팩토리 함수(factory function)를 쓰도록 만들어져 있다.class Investment { ... }; /* 여러 형태의 투자를 모델링한 최상위 클래스 Investment */Investment* createInvestment(); /* Investment 클래스 계통의 객체를 동적 할당하고 그 포인터를 반환하는 팩토리 함수 */  createInvestment 함수를 통해 얻은 객체를 사용할 일이 없.. 2022. 1. 23.
전문가를 위한 C++ | Chapter 07 메모리 관리(상) 7.1 동적 메모리 다루기 메모리는 컴퓨터의 로우 레벨 구성 요소에 속하지만, 실력 있는 C++ 프로그래머가 되기 위해서는 동적 메모리를 처리하는 과정을 확실하게 이해하고 넘어가야 한다. 7.1.1 메모리 작동 과정 이 책에서는 메모리 한 칸을 레이블이 달린 상자로 표현한다. 여기서 레이블은 그 메모리를 사용하는 변수의 이름에 해당한다. 그리고 상자에 담긴 데이터는 그 변수에 현재 저장된 값이다. int i = 10; int* ptr = nullptr; ptr = new int; 예를 들어 그림 7-1 왼쪽은 다음 코드를 실행한 후의 메모리 상태를 표현한 것이다. 지역 변수 i를 자동 변수(automatic variable)라고 부르며 스택에 저장된다. 프로그램 실행 흐름이 이 변수가 선언된 유효 범위(.. 2022. 1. 20.