시작은 미미하나 끝은 쥬쥬하리라.

분류 전체보기 105

[effective C++] Chapter 03 : 14. 자원 관리 클래스의 복사 동작에 대해 진지하게 고찰하자

14. 자원 관리 클래스의 복사 동작에 대해 진지하게 고찰하자 RAII 클래스 RAII 객체 복사 이것만은 잊지 말자 ! RAII 클래스 힙에 생기지 않는 자원은 auto_ptr과 tr1::shared_ptr 등의 스마트 포인터로는 처리해주는 것이 힘들다. 따라서 우리는 자원 관리 클래스를 만들 필요가 있다. 뮤텍스 타입의 객체를 조작하는 C API의 lock과 unlock을 사용하면서 뮤텍스의 잠금을 관리하는 클래스를 하나 만들었다고 가정해보자. 이 클래스는 RAII(자원 획득 즉 초기화) 기법을 따라 구성하면서 생성 시에 자원을 획득하고 소멸 시에 그 자원을 해제한다고 가정하고 코드는 아래와 같다. 사용자는 lock을 사용할 때 RAII 기법에 맞추어 사용한다. RAII 객체의 복사 만약 여기서 lo..

Study/Effective C++ 2023.08.12

[effective C++] Chapter 03 : 13. 자원 관리에는 객체가 그만 !

13. 자원 관리에는 객체가 그만 ! 객체의 소멸 관리 auto_ptr TR1-RCSP 이것만은 잊지 말자 객체의 소멸 관리 투자를 모델링해 주는 클래스를 가지고 작업을 한다고 가정하자. Investment라는 최상위 클래스가 있고 그 밑에 구체적인 형태의 투자 클래스가 있다고 생각하고 Investment에서 파생된 클래스의 객체를 얻어내기 위한 용도로 CreateInvestment()라는 이름의 팩토리 함수가 정의된다고 하면 아래와 같은 코드가 될 것이다. 위 CreateInvestment 함수를 통해 얻어낸 객체의 삭제는 호출해준 쪽에서 해주어야 한다. 따라서 팩토리 함수의 호출과 메모리 해제를 하는 함수 f를 아래와 같이 구현해 보았다. 하지만 위의 함수는 중간에 return을 만나거나 contin..

Study/Effective C++ 2023.08.04

[effective C++] Chapter 02 : 12. 객체의 모든 부분을 빠짐없이 복사하자

12. 객체의 모든 부분을 빠짐없이 복사하자 부분 복사 클래스 상속의 부분 복사 이것만은 잊지 말자 ! 부분 복사 객체 지향 시스템 중 설계가 잘 된 코드를 보면 객체의 복사를 수행하는 함수의 종류는 딱 두 가지이다. 복사 생성자와, 대복사 대입 연산자가 이들이다. 하지만 컴파일러가 기본적으로 선언하는 것이 아닌 사용자가 직접 정의해서 사용하는 경우 간혹 문제가 발생하곤 한다. 예시를 위해 고객을 나타내는 클래스와 복사 함수를 호출할 때마다 로그를 남기는 함수가 있다고 가정해보자. 위의 코드는 문제가 없으나 데이터 멤버를 Customer에 추가하면 문제가 발생하기 시작한다. 위와 같이 복사 생성자와 복사 대입 연산자는 그대로 정의되어 있고 Date라는 클래스와 Date형 객체 lastTransaction..

Study/Effective C++ 2023.08.04

[effective C++] Chapter 02 : 11. operator=에서는 자기대입에 대한 처리가 빠지지 않도록 하자

11. operator=에서는 자기대입에 대한 처리가 빠지지 않도록 하자 자기 대입 operator= 자기 참조 에러 대책 이것만은 잊지 말자 ! 자기 대입 위와 같은 코드는 일반적이지 않다. 하지만 문법상 문제가 있지도 않다. 그나마 위는 조금 눈에 띄는 형태의 자기 대입이 이루어지고 있지만 아래의 코드를 확인해보자. 첫번째 문장에서 i와 j는 같은 값일 가능성을 가지고 있고 두번째 문장의 x와 y 역시 같을 가능성을 가지고 있다. 즉, 자기 대입의 가능성을 가지고 있지만 많은 코드 속에서 위와 같은 코드를 발견하기란 쉽지 않다. 우리는 자원 관리 용도로 객체를 생성해야하고 이러한 객체들이 복사될 때 잘 동작하도록 해야하는데 유의해야하는 것이 대입 연산자이며 여러 곳에서 하나의 객체를 참조하는 중복 참..

Study/Effective C++ 2023.08.03

[effective C++] Chapter 02 : 10. 대입 연산자는 *this의 참조자를 반환하게 하자

10. 대입 연산자는 *this의 참조자를 반환하게 하자 C++ 대입 연산자의 반환 이것만은 잊지 말자 ! C++ 대입 연산자의 반환 C++의 대입 연산은 사슬과 같은 형태로 이루어지며 우측 연관이라는 성질을 가지고 있다. 위의 코드를 보면 x, y, z를 선언하고 이를 15로 초기화해주고 있는데, 사실은 z의 초기화를 진행하고 다시 z를 y에 대입한 이후에 y를 x에 대입하면서 우측부터 순차적으로 초기화하는 형태로 이루어진다. 중요한 것은 대입 연산자(=)이 좌변 인자에 대한 참조자의 형태로 반환하도록 구현되어 있다는 점이다. 아래의 코드에는 참조자를 반환하는 것에 대한 관례를 알아보는 코드이다. 위는 단순 대입형 연산자이지만 좌변 객체의 참조자를 반환하게 만드는 규칙은 모든 형태의 대입 연산자에서 지..

Study/Effective C++ 2023.08.03

[effective C++] Chapter 02 : 09. 객체 생성 및 소멸 과정 중에는 절대로 가상 함수를 호출하지 말자

09. 객체 생성 및 소멸 과정 중에는 절대로 가상 함수를 호출하지 말자 객체 생성 및 소멸의 이해 비가상 멤버 함수 이것만은 잊지 말자 ! 객체 생성 및 소멸의 이해 객체를 생성 및 소멸하는 과정 중에는 가상 함수를 호출하는 것은 금기이다. 이해를 위해 아래의 코드를 보도록 하자. 위 클래스는 주식 거래를 표현하는 클래스이다. 기본 클래스이자 순수 가상 함수를 포함한 추상 클래스인 Transaction 클래스 아래 파생 클래스가 2개 정의되어 있으며, 주식 관련 객체가 생성될때마다 로그를 남기도록 logTransaction() 함수가 구현되어 있는 형태이다. 결론적으로 위와 같이 순수 가상 함수를 기본 클래스의 생성자에서 호출하는 경우에는 컴파일 에러가 발생한다. 기본적으로 파생 클래스가 생성될 때는 ..

Study/Effective C++ 2023.08.03

[effective C++] Chapter 02 : 08. 예외가 소멸자를 떠나지 못하도록 붙들어 놓자

08. 예외가 소멸자를 떠나지 못하도록 붙들어 놓자 예외와 소멸자 이것만은 잊지 말자 ! 예외와 소멸자 위 코드는 vertor 타입의 객체 v를 생성한다. 객체 v 혹은 v2, v2 ... 등 vertor 타입의 객체 소멸에 대한 책임은 벡터에게 있다. 하지만 만약 vector 타입 객체, 여기서는 Widget의 소멸자가 호출되는 과정에서 예외가 발생된다면 어떻게 될까 ? 프로그램은 미정의 동작을 발생하고 그 원인은 바로 예외를 방치하는 소멸자에게 원인이 있다. C++은 예외를 내보내는 소멸자를 좋아하지 않는다. 더 구체적인 예시를 위해 아래의 코드를 보자. 위 코드는 DBConnection 객체에 대해 close를 사용자가 직접 호출해야하는 설계이다. 사용자의 망각을 차단하기 위해 해당 객체에 자원 관..

Study/Effective C++ 2023.07.30

[effective C++] Chapter 02 : 07. 다형성을 가진 기본 클래스에서는 소멸자를 반드시 가상 소멸자로 선언하자

07. 다형성을 가진 기본 클래스에서는 소멸자를 반드시 가상 소멸자로 선언하자 팩토리 함수 가상 소멸자 순수 가상 소멸자 이것만은 잊지 말자 ! 팩토리 함수 만약 위와 같이 시간에 관한 정보를 담고 있는 TimeKeeper 객체가 있고, 사용자들은 시간 정보에 접근하고 싶어한다고 가정해보자. 이때, 이 시간 기록 객체에 대한 포인터를 손에 넣는 용도로 함수를 정의하면 이것이 팩토리 함수이다. 팩토리 함수의 정확한 정의는 "새로 생성된 파생 클래스 객체에 대한 기본 클래스 포인터를 반환하는 함수" 이다. 위와 같이 코드를 정의하면 TimeKeeper에서 파생된 클래스를 통해 동적으로 할당된 객체의 포인터를 반환 받을 수 있다. 하지만 함수에서 반환되는 객체는 힙에 있게 되므로 메모리의 누수를 막기 위해 해..

Study/Effective C++ 2023.07.30

[effective C++] Chapter 02 : 06. 컴파일러가 만들어낸 함수가 필요 없으면 확실히 이들의 사용을 금해 버리자

06. 컴파일러가 만들어낸 함수가 필요 없으면 확실히 이들의 사용을 금해 버리자 복사 생성자 / 복사 대입 연산자 private 선언 클래스 멤버 및 friend 함수의 호출 제한 복사 방지를 의미하는 클래스 정의 이것만은 일지 말자 ! 복사 생성자 / 복사 대입 연산자 private 선언 만약 하나의 객체가 복사되는 것을 막고 싶다면 어떻게 하는 것이 좋을까 ? 예를 들어, HomeForSale이라는 클래스가 있고 이는 자산을 의미하며 자산은 유일하기 때문에 이것의 사본을 만드는 것은 이치에 맞지 않다고 한다면, 해당 객체를 복사하려 하는 코드는 컴파일 되지 않게 만드는 것이 맞다. 해답은 컴파일러가 자동으로 생성하는 모든 함수는 public으로 처리 된다는 사실에 있다. 따라서 자동으로 생성되는 복사..

Study/Effective C++ 2023.07.30

[effective C++] Chapter 02 : 05. C++가 은근슬쩍 만들어 호출해 버리는 함수들에 촉각을 세우자

05. C++가 은근슬쩍 만들어 호출해 버리는 함수들에 촉각을 세우자 Empty Class 복사 생성자 / 복사 대입 연산자의 역할 이것만은 잊지 말자 ! Empty Class C++의 컴파일러는 개발자가 클래스 안에 멤버 함수를 직접 선언해주지 않으면 컴파일러가 저절로 선언해주는 것이 있다. 기본 생성자, 복사 생성자, 복사 대입 연산자, 소멸자는 선언이 되어있지 않은 경우 컴파일러가 자동적으로 선언하는 함수에 해당하고 이들은 모두 public 멤버 그리고 inline 함수로 선언된다. 따라서 아래의 두 클래스는 동일하다. 컴파일러가 기본 함수를 자동 생성하는 시점은 컴파일러가 판단해서 해당 함수가 필요하다고 생각되는 시점이며 위와 같이 코드가 선언되어 있을 때, 각각의 함수들이 생성되는 시점은 아래와..

Study/Effective C++ 2023.07.29