본문 바로가기

C++

(9)
항목 17: new 로 생성한 객체를 스마트 포인터에 저장하는 코드는 별도의 한 문장으로 만들자 자원 누출 가능성 스마트 포인터 생성 코드 처리 우선순위를 알려주는 함수와 동적으로 할당한 Widget 객체에 대해 우선순위에 따라 처리를 적용하는 함수가 있다고 하자 int priority(); void processWidget(std::shard_ptr pw, int priority); //shared_ptr 을 통해 자원관리호출시 아래와 같이 쓰면 컴파일 에러가 난다! processWidget(new Widget, priority());shared_ptr 의 생성자는 explicit 로 선언되어 있기 때문에, new Widget 에 의해 만들어진 포인터가 shared_ptr 타입의 객체로 바뀌는 암시적 변환은 일어나지 않는다. 그래서 아래와 같이 써줘야 한다. processWidget(shared_..
항목 16: new 및 delete 를 사용할 때는 형태를 반드시 맞추자 delete 사용시 주의 사항 아래 코드를 보고 문제점을 찾아보자. string *stringArray = new string[100]; delete stringArray;그렇다. new 는 배열을 할당했는데, delete 는 그렇지 않다. stringArray 가 가리키는 100 개의 string 객체중 99개는 정상적인 소멸과정을 거치지 못할 가능성이 크다. new 와 delete 연산자의 동작 new 연산자를 사용해 어떤 객체를 동적 할당하게 되면, 두 가지의 내부 동작이 이뤄진다. 1) 메모리가 할당된다. (operator new 라는 이름의 함수가 쓰인다. 항목 49. 51 참조) 2) 할당된 메모리에 대해 한 개 이상의 생성자가 호출된다. delete 연산자를 쓸 때는 다음과 같은 두 가지 내..
항목 15: 자원 관리 클래스에서 관리되는 자원은 외부에서 접근할 수 있도록 하자 자원 관리 클래스의 자원 접근 자원에 접근하려 하는 예 아래 createInvestment 로 자원을 만든 후, pInv 에 넘겨주는 경우를 생각해보자 (항목 13 예제) shared_ptr pInv(createInvestment());그리고 Investment 객체를 사용하는 함수가 다음과 같이 정의 되어있다고 하자 int daysHeld(const Investment *p); //그러면 이렇게 호출하고 싶겠죠 int days = daysHeld(pInv); 그러나 위와 같이 할 경우 컴파일이 되지 않는다. daysHeld 는 Investment * 타입의 포인터를 원하는데 , shared_ptr 타입을 넘기고 있으니 안되는 것! RAII 클래스 객체의 자원 변환 위 문제를 해결하기 위해서는 결국 RA..
항목 14: 자원 관리 클래스의 복사 동작에 대해 진지하게 고찰하자 자원 관리 클래스에 대한 고찰 항목 13에서 처럼 힙 기반 자원이 아니라면 어떻게 관리해야 하는가? 자원 관리 클래스를 결국 만들어야 한다. 예를 들어 Mutex 타입의 객체를 조작하는 C API 를 사용중이라고 가정해보자. 해당 API 는 lock, unlock 함수를 제공한다. void lock(Mutex *pm); void unlock(Mutext *pm);이전에 걸어 놓은 뮤텍스 잠금을 잊지 않고 풀어주기 위한 용도의 잠금 관리 클래스를 만들고 싶다면 이 클래스는 RAII 법칙을 따라 구성한다. == 생성 시에 자원을 획득, 소멸 시에 자원을 해제! 잠금 관리 클래스 class Lock { public: explicit Lock(Mutext *pm) : mutexPtr(pm){ lock(mutex..
항목 13: 자원 관리에는 객체가 그만! 참고 : 책에서는 auto_ptr 을 예로 들어서 계속 설명하지만, auto_ptr 은 사용권장 되고 있지 않기 때문에 관련한 부분은 여기에 적지 않았다. 스마트 포인터 동적 할당한 객체의 문제 아래와 같이 동적할당한 객체를 얻어내고, 해당 객체를 사용한 뒤에 delete 해주는 함수가 있다하자. void f() { Investment *pInv = createInvestment(); ... delete pInv; }이 경우 해당 객체를 삭제 하지 못하는 경우가 발생할 수 있다. 1) delete 이전에 함수가 리턴되는 상황 2) 도중에 예외가 던져져서 delete를 하지 못하는 상황 createInvestment 로 얻어낸 자원이 항상 해제되도록 하는 방법은, 자원을 객체에 넣고 그 자원을 소멸자가 맡..
항목 31 : 파일사이의 컴파일 의존성을 줄이자 인터페이스와 구현의 분리 c++ 의 class definiton 는 클래스 인터페이스 + 구현 세부사항까지 지정 할 수 있어서 c++ 은 인터페이스와 구현을 깔끔하게 분리하기 힘들다. 예를 들어 아래 코드처럼 Person 구현의 세부사항에 속하는 Date, Address 정의된 정보를 가져오기 위해 "date.h", "address.h" 들을 물어와야 한다. #include #include "date.h" #include "address.h" class Person { public: Person(const Date& birthday, const Address& addr); private : std::string name; Date theBirthDate; //구현 세부사항 Address theAddres..
c++ idiom C++ Idiom 프로그래밍시 발생하는 문제를 해결하기 위한 기법 같은 것. c++ 의 언어적인 특성에 기반한 팁 문제해결 패턴 같은 것들이라고 할 수 있다. https://en.wikibooks.org/wiki/More_C%2B%2B_Idioms (다양한 기법과 패턴들이 나와있다.) 여기서는 널리 쓰이는 기법들만 소개하고자 한다. PImpl (Pointer to Implementation) 포인터를 이용해서, 실제 구현체를 감춰두는 기법. 아래 두가지의 장점이 있다. 1) 전방 선언을 통한 컴파일 시간 단축 2) 인터페이스와 구현의 분리 실제 구현부를 인터페이스에 작성하지 않아서, 변경되더라도 인터페이스는 변경하지 않는다. 인터페이스가 변경되지 않았기 때문에 client 코드를 다시 컴파일 할 필요가 ..
Move Semantic Move Semantics (이동 문법) 이동 생성자와 이동 할당 연산자를 구현한 클래스를 move semantic 을 갖고 있다고 한다. 변수(이름으로 참조 할 수 있는 데이터)는 깊은 복사를 하고, 임시값(이름으로 참조 할 수 없는 데이터)이 데이터를 전송한다는 컨셉 객체에 대한 메모리 소유권을 이동시키면서 댕글링 포인터, 메모리 릭을 방지 ( (해제된 메모리를 가리키고 있는 것을 댕글링 포인터라고 한다.) 불필요한 복사를 줄일 수 있다. 벡터 같은 컨테이너에 원소 복사시 유용하게 쓰인다. 객체를 컨테이너에 가져 올 때, 객체 복제가 아닌 이동시킬 수 있다. 임시 객체를 리턴할 때도, 일반 복제 대입 연산 대신에 이동 연산을 이용한다.. lvalue , rvalue lvalue : 주소값을 취할 수 ..