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

Study/Effective C++ 17

[effective C++] Chapter 03 : 17. new로 생성한 객체를 스마트 포인터에 저장하는 코드는 별도의 한 문장으로 만들자

17. new로 생성한 객체를 스마트 포인터에 저장하는 코드는 별도의 한 문장으로 만들자 new 객체와 스마트 포인터 이것만은 잊지 말자 ! new 객체와 스마트 포인터 처리 우선 순위를 알려주는 함수가 하나 있고, 동적으로 할당한 Widget 객체에 대해 어떤 우선 순위에 따라 처리를 적용하는 함수가 있다고 가정하자. 자원 관리는 동적 할당된 Widget 객체에 대해 shared_ptr을 사용하도록 만들어졌다고 하고 processWidget 함수를 호출한다. 하지만 위의 코드는 컴파일 되지 않는다. 이유는 shraed_ptr의 생성자는 explicit로 선언되어 있기 때문에 new Widget으로 Widget 형 포인터가 shared_ptr 형태로 바뀌는 암시적 변환이 불가능하기 때문이다. 위 함수에는..

Study/Effective C++ 2023.08.13

[effective C++] Chapter 03 : 16. new 및 delete를 사용할 때는 형태를 반드시 맞추자

16. new 및 delete를 사용할 때는 형태를 반드시 맞추자 단일 객체 / 배열 객체 메모리 해제 typedef 메모리 해제 이것만은 잊지 말자 ! 단일 객체 / 배열 객체의 메모리 해제 위 코드는 string 배열을 가리키는 stringArray 포인터 객체를 생성하고 메모리 해제까지 하는 코드이다. 하지만 위 코드는 프로그램을 미정의 동작으로 빠지게 만든다. 그 이유는 위 코드만으로 100번의 소멸자 호출이 이루어지지 못하기 때문이다. new 연산을 사용하면 메모리가 할당이 되고, 생성자가 호출이 된다. 반면, delete 연산을 사용하면 소멸자가 호출되고 메모리가 해제되는 과정을 거친다. 여기서 delete 연산이 적용되는 객체의 개수는 소멸자가 호출되는 횟수와 동일하다. 기본적으로 단일 객체..

Study/Effective C++ 2023.08.13

[effective C++] Chapter 03 : 15. 자원 관리 클래스에서 관리되는 자원은 외부에서 접근할 수 있도록 하자

15. 자원 관리 클래스에서 관리되는 자원은 외부에서 접근할 수 있도록 하자 get() 함수 암시적 변환 함수 이것만은 잊지 말자 ! get() 함수 아래와 같이 스마트 포인터를 사용하여 함수 호출 결과를 담고, 어떤 동작을 하는 함수를 정의하여 그 인자로 스마트 포인터를 넘겼을 때의 결과를 보자. 위에서 daysHeld 함수는 Investment* 타입의 포인터를 원하는데 shared_ptr을 인자로 넘기고 있기 때문에 에러가 발생한다. 이를 해결하기 위해서 명시적 변환 혹은 암시적 변환이 필요한데, shared_ptr과 auto_ptr은 get()이라는 멤버 함수를 통해 명시적 변환을 수행할 수 있게 제공해주고 있다. get() 함수를 통해 우리는 스맡트 포인터 객체에 들어 있는 실제 포인터의 사본을..

Study/Effective C++ 2023.08.13

[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