728x90

13. 자원관리에는 객체가 그만이다. 

   - 자원누출을 막기위해, 생성자 안에서 자원을 획득하고 소멸자에서 그것을 해제하자.

     RAII(Resource Acquisition is Initialize) 방식을 사용하자.

     (RAII :생성자에서 할당하고, 에러 상황에서도 호출이 보장되는 같은 객체의 소멸자 같은 것에서 리소스를 해제)

   - 일반적인 RAII클래스는 tr1::shared_ptr과 auto_prt이다.

     (둘 중 tr1:shared_ptr이 복사시의 동작이 직관적이기 때문에 좋다.)

     (auto_ptr은 복사되는 객체(원본 객체)를 null로 만들어 버린다.)

 

14. 자원관리 클래스의 복사 동작에 대해 진지하게 고찰하자.

   - RAII객체의 복사는 그 객체가 관리하는 자원의 복사 문제를 안고가고 때문에 그 자원을 어떻게 복사하느냐에 따라 RAII객체의 

     복사 동작이 결정된다.

   - RAII클래스에 구현하는 일반적인 복사동작은 복사를 금지하거나 참조 카운팅을 해주는 선으로 마무리한다.

 

15. 자원관리 클래스에서 관리되는 자원은 외부에서 접근할 수 있도록 하자.

   - 실제 자원을 직접 접근해야 하는 기존 API가 많으므로 RAII클래스를 만들때는 그 클래스가 관리하는 자원을 얻을 수 있는 방법

     을 만들자.

   - 자원 접근은 명시적 변환 혹은 암시적 변환을 통해 가능하다.

     (명시적변환은 안전성에서 우수하고, 고객편의성을 놓고보면 암시적변환이 우수하다.)

 

16. new 및 delete를 사용할 때는 형태를 반드시 맞추도록 하자.

   - new 표현식에 []가 있으면, delete표현식에도 []를 써야 한다.

   - new 표현식에 []가 없으면 delete표현식에도 []를 사용해서는 안된다.

 

17. new로 생성한 객체를 스마트포인터에 저장하는 코드는 별도의 한 문장으로 만들자.

   - 예외가 발생할 때 디버깅을 하기 힘든 자원 누출이 초래될 수 있다.

     어떤 함수가 있고 동적으로 할당한 객체에 스마트포인터를 사용할 시

     int process();

     void foo(std::tr1::shared_ptr<ABC>(new ABC), process);

    

     위 소스는 컴파일은 가능하나 C++컴파일러는 함수 호출시 이루어지는 연산의 순서를 정하는데 있어서 상당한 자유도를 갖고 있

     으므로 (JAVA나 C#은 매개변수의 평가순서가 특정하게 고정) 컴파일러에 따라 자원 누출을 초래하는 결과가 생길 수도 있다.

 

     // 해결책

     std::tr1::shared_ptr<ABC> pw(new ABC);

     foo(pw, process());

     이렇게 하면 문장과 문장 사이에 있는 연산들이 컴파일러의 재조정을 받을 여지가 적어지므로 자원 누출 가능성이 없어진다.

 

18. 인터페이스 설계는 제대로 쓰기엔 쉽게, 엉터리로 쓰기엔 어렵게 하자.

   - 좋은 인터페이스 자체는 제대로 쓰기 쉽게, 엉터리로 쓰기에 어렵게 되어 있다.

   - 사용자의 실수를 방지하도록 새로운 타입을 만들거나, 타입에 대한 연산을 제한하기, 객체의 값에

     대해 제약걸기, 자원관리 작업을 사용자 책임으로 놓지 않기 등이 있다.

   - tr1::shared_ptr은 사용자 정의 삭제자를 지원한다. 이 특징 때문에 교차 DLL 문제를 막아주며, 뮤

     텍스등을 자동으로 잠금 해제하는데 쓸 수 있다.

 

   * 교차 DLL(Cross-DLL) : 객체 생성시 dll의 new를 썻는데 그 객체를 삭제할 때는 이전의 dll과 다

     른 dll에 있는 delete를 썻을 경우 발생한다.

 

19. 클래스 설계는 타입 설계와 똑같이 취급하자.

   - 새로 정의한 타입에 객체 생성 소멸은 어떻게 할 것인가?

   - 객체 초기화는 객체 대입과 어떻게 달라야 하는가?

   - 새로운 타입으로 만든 객체가 값에 의한 전달일 경우 어떤 의미인가?

   - 새로운 타입이 가질 수 있는 적법한 값에 대한 제약은 무엇으로 할 것인가?

   - 기존의 클래스 상속 계통망에 맞출 것인가?

   - 어떤 종류의 타입 변환을 허용할 것인가?

   - 어떤 연산자와 함수를 두어야 의미가 있는가?

   - 표준 함수중 어떤 것을 허용하지 말아야하는가(private member function)?

   - 멤버에 대한 접근 권한을 어느 쪽에 줄 것인가?

   - 선언되지 않은 인터페이스로 무엇을 둘 것인가?

   - 새로 만드는 타입이 얼마나 일반 적인가?

   - 정말로 꼭 필요한 타입인가?

   빠짐 없이 점검해보도록 하자.

 

20. '값에 의한 전달'보다는 '상수 객체 참조자에 의한 전달'방식을 사용하자.

   - 대체 적으로 효율 적일 뿐만 아니라(생성자, 소멸자가 호출되지 않음) 복사 손실 문제도 막아준다.

   - 단, 기본 제공 타입(int등), STL iterator, 펑터(함수 객체)에는 맞지 않다.

   - 이들은 값에 의한 전달이 더 적절하다.

 

21. 함수에서 객체를 반환해야 할 경우에 참조자를 반환하려고 들지 말자.

   - 함수 수준에서 새로운 객체를 만드는 방법은 두 가지 이다.(스택과 힙)

   - 지역 스택 객체에 대한 포인터나 참조자를 반환하는 일.

   - 힙에 할당된 객체에 대한 참조자를 반환하는 일.

   - 지역 정적 객체에 대한 포인터나 참조자를 반환하는 일.

   - 그런 객체가 두 개 이상 필요해질 가능성이 있다면 하지 말도록 하자.

 

22. 데이터 멤버가 선언될 곳은 private 임을 명심하자.

   - 데이터 멤버는 private로 선언하고 문법적으로 일관성 있는 데이터 접근 통로를 제공해주자.

   - protected는 public 보다 더 많이 보호 받고 있는 것이 아니라는 것을 명심하자.

 

23. 멤버 함수보다는 비 멤버 비프랜드 함수와 더 가까워지자.

   - 관련 기능을 구성하는데 있어서 패키지 유연성(package flexibility)가 높아진다.

   - 컴파일 의존도를 낮추며 함수의 확장성도 높일 수 있다.

   - 클래스 내부에서 멤버 함수를 정의하는 것도 좋지만

      void foo(Student& Stu)

      {

           stu.clearHistory();

           stu.clearList();

       }

     식으로 사용하는 것도 좋다는 것이다.

 

24. 타입 변환이 모든 매개 변수에 대해 적용되어야 한다면 비 멤버 함수를 선언하자.

   - 어떤 함수에 들어가는 모든 매개 변수(this 포인터가 가리키는 객체 포함)에 대해 타입 변환이 필요하다면 

     그 멤버 함수는 비멤버이어야 한다.

 

25. 예외를 던지지 않는 swap에 대한 지원도 생각해보자.

   -  std::swap이 타입에 대해 느리게 동작할 여지가 있다면 swap 멤버 함수를 제공하자(단 예외는 던지지 않게 만들 것)

   -  멤버 swap을 제공 했으면, 이 멤버를 호출하는 비멤버 swap도 제공하자.

   - 클래스(템플릿이 아닌)에 대해서는 std::wap을 만들도록 하자.

   - 사용자 입장에서 swap을 호출할 때는 std::swap에 대한 using 선언을 넣어준 후에 네임 스페이스 한정없이 swap을 호출하자.

   - 사용자 정의 타입에 대한 std 템플릿을 완전 특수화 하는 것이 가능하지만 std에 어떤 것이라도 새로 추가하려고 들지는 말자.

 

   - 1. 두 객체의 값을 맞바꾸는 함수를 swap이라 하고, public 멤버 함수로 둔다.

   - 2. 클래스나 템플릿이 들어 있는 네임 스페이스와 같은 곳에 비멤버 swap을 만든다. 그리고 1번에

         서 만든 swap 멤버 함수를 이 비멤버 함수가 호출하도록 한다.

   - 3. 새로운 클래스를 만든다면 그 클래스에 대한 std::swaap의 특수화 버전을 준비하자.

         이 버전에서도 swap 멤버 함수를 호출하도록 하자.

         template<typename T>

         {

              using std::swap;     // std::swap을 함수 안으로 끌어옴.

              ...

              swap(obj1, obj2);    // T타입의 전용 SWAP을 호출.

         }

 

출처 : http://blog.naver.com/sorkelf/40146367692

728x90

+ Recent posts