9월 11, 2017

[EC++ 22] Declare data members private.


  • Data member를 private으로 설정함으로써 data member로의 accessibility를 더욱 세밀하게 컨트롤할 수 있다.
  • Data member를 functional interface 뒤에 숨김으로써 다양한 구현상 이점(유연함)을 얻을 수 있다.
  • Data member를 클라이언트에게서 숨기고 encapsulate 함으로써 클래스 불변성을 보장할 수 있으며, 후에 implementation decision 변경 시 좀 더 자유로울 수 있다.
  •  public (또는  protected )은 uncapsulated과 같은 의미로, 이는 해당 부분 및 연관된 부분에 대한 클래스 수정이 불가능함을 의미한다. 따라서, encapsulation의 관점에서는 사실상  public ( protected ) 이거나  private , 단 두가지의 선택지만이 존재한다.



Summary

  • Declare data members  private . It gives clients syntactically uniform access to data, affords fine-grained access control, allows invariants to be enforced, and offers class authors impementation flexibility.
  •  protected  is no more encapsulated than  public .

Reference

  • Effective C++ by Scott Meyers

7월 09, 2017

[EC++ 21] Don't try to return a reference when you must return an object.

  • reference는 이미 존재하는 object를 가리키는, '이름'일 뿐임을 명심하라.
  • function은 heap, 혹은 stack 오직 2가지 방법으로만 새로운 object를 생성할 수 있다.
  • 새로운 object를 리턴하는 제대로 된 방법은, object를 새로 만들어서 리턴하는 방법 뿐이다.
  • C++은 함수가 새로운 object를 생성하여 리턴할 때 컴파일러가 이런 일련의 과정을 최적화하는 것을 허용한다.
  • ex. Ellsion, Return Value Optimization 참조

  • 만약 리턴 값으로 reference와 new object 사이에서 선택을 해야하는 경우가 생긴다면, 다른 부분에 대해서 고민할 것 없이, 의도된 대로 올바른 동작을 제공하는 방식을 택해라. 최적화 등 기타 골치 아픈 문제들은 컴파일러 제작자가 고민하도록 내버려둬라.


Summary

  • Never return a pointer or reference to a local stack object, a reference to a heap-allocated object, or a pointer or reference to a local static object if there is a chance taht more than one such object will be needed. (Item4 provides an example of a design where returning a reference to a local static is reasonale, at least in single-threaded environments.)

Reference

  • Effective C++ by Scott Meyers

6월 25, 2017

[EC++ 20] Prefer pass-by-reference-to-const to pass-by-value.


Pass-by-reference-to-  const  

의 좋은 점
  • pass-by-value 로 인한 불필요한 ctor와 dtor의 호출을 막을 수 있다.
  • Slicing problem을 막을 수 있다.
  • param.로 어떤 객체를 받을 때, param.의 타입이 받으려는 객체의 base 클래스인 경우, param.로 그 객체를 받아 복사생성하는 과정에서 객체에서 derived 된 특성(data, function)이 잘려나가게 되는데, 이를 Slicing problem이라 한다.
  • 단, built-in type의 경우 pass-by value가 더 효율적이다. 이는 iterator나 function object in STL에도 해당되는데, 이런 기능들이 pass by value로 건네주도록 설계되었기 때문이다.
  • 작은 크기의 객체라고 해서 반드시 pass-by-value가 효과적인 것은 아니다.
  • 몇몇 컴파일러의 경우 built in type과 User defined type를 다르게 취급하는 경우가 있다. 또한 나중에 type의 설계가 변경됨에 따라 user defined type의 크기가 더 커지는 등의 변화가 있을 수도 있다.

  • 일반적으로, pass-by-value로 넘겨도 적은 비용이 든다고 보장할 수 있는 type은 built-in type과 STL iterator 또는 fucntion object type이다.


Summary

  • Prefer Pass-by-reference-to-  const   over pass-by-value. It's typically more efficient and it avoids the slicing problem.
  • The rule doesn't apply to built-in types and STL iterator and function object types. For them, pass-by-value is usually appropriate.

Reference

  • Effective C++ by Scott Meyers

[EC++ 19] Treat class design as type design

  • 다른 OOP 언어들과 마찬가지로, C++에서 새로운 클래스를 만든다는 것은 새로운 타입을 만드는 것과 같다.
  • 좋은 타입의 조건
    • 자연스러운 문법
    • 직관적인 문법
    • 하나 이상의 효율적인 구현 방법이 존재
    • 클래스 멤버 함수를 어떻게 선언되었는가에 따라 그 멤버 함수의 성능이 영향을 받을 수 있다


효율적인 클래스를 디자인하기 위해 생각해봐야 할 점

  • How should objects of your new type be created and destroyed?
  • How should object initialization differ frome object assignment?
  • What does it mean for objects of your new type to be passed by value?
  • What are the restrictions on legal values for your new type?
  • Does your new type fit into an inheritance graph?
  • 어떤 클래스를 상속 받으면 그 클래스의 디자인의 제한 요건을 따르게 되는데, 특히 virtual, non-virtual 과 같은 제한이 그렇다. 만약 자신이 설계한 클래스를 다른 클래스가 상속 받을 수 있도록 허용한다면 어떤 멤버가 virtual일지 결정해야하는데, 특히 destructor를 virtual 로 선언해야 한다.

  • What kind of type conversions are allowed for your new type?
  • What operators and functions make sense for the new type?
  • 어떤 멤버 함수를 제공할 것인가?

  • What standard founctions should be disallowed?
  • 무엇을 private으로 선언할 것인가?

  • Whoshould have access to the members of your new type?
  • What is the "undeclared interface" of your new type?
  • performance와 exception safety, 그리고 resource usage(locks, dynamic memory)에 있어 어떤 보장을 제공할 것인가?

  • How general is your new type?
  • class가 아니라 class template을 만들어야 할 수도 있다.

  • Is a new type really what you need?



Summary

  • Class design is type design. Before defining a new type, be sure to consider all the issues discussed in this Item.

Reference

  • Effective C++ by Scott Meyers

5월 29, 2017

[EC++ 18] Make interfaces easy to use correctly and hard to use incorrectly.

  • 클라이언트에게 어떤 것을 해야하는 책임을 지우는 인터페이스는 잘못 사용되기 쉽다. 클라이언트는 책임을 종종 잊어버리기 때문이다.
  • cross-DLL problem
  • 어떤 오브젝트가 한 DLL에서 생성된 후 다른 DLL에서 삭제되는 경우 런타임 오류를 일으키는 현상.  std::shared_ptr 은 deletor를 지정할 수 있는데, 이를 통해 cross-DLL problem을 피할 수 있다.



Summary

  • Good interfaces are easy to use correctly and hard to use incorrectoly. You should strive for these characteristics in all your interfaces.
  • Ways to facilitate correct use include consistency in interfaces and behavioral compatibility with built-in type.
  • Ways to prevent errors include creating new types, restricting operations on types, constraining object values, and eliminating client resource management responsibilities.
  •  tr1::shared_ptr  supports custom deleters. This prevents the cross DLL problem, can be used to automatically unlock mutexes (item 14), etc.

Reference

  • Effective C++ by Scott Meyers

3월 23, 2017

[EC++ 17] Store  new ed objects in smart pointers in standalone statements.


processWidget(std::tr1::shared_ptr(new Widget), priority());

위 코드는 1. new  메모리 할당 ->  shared_ptr  ctor call ->  priority()  call의 세 단계에 걸쳐 수행된다. 그런데 컴파일러에 의해  shared_ptr  ctor call과  priority()  call의 순서가 바뀔 수 있는데, 이 경우  priority() 가 예외를 던지면 memory leak이 발생하게 된다. 따라서  new ed object를   shared_ptr 에 넘겨주는 부분은 별도의 문장으로 따로 빼내는 것이 좋다.



Summary

  • Store  new ed objects in smart pointers in standalone statements. Failure to do this can lead to subtle resource leaks when exceptions are thrown.

Reference

  • Effective C++ by Scott Meyers

3월 22, 2017

[EC++ 16] Use the same form in corresponding uses of   new   and   delete  


  • 일반적으로 single object 와 array는 메모리 상의 구조가 다르다. single object는 메모리 상에 해당 object가 차지하는 공간만이 할당되지만, array는 메모리 상에 array의 크기를 먼저 기록하고 그 다음에 실제 object의 공간을 할당한다.
  • single object와 array는 메모리 상에 할당 되는 구조가 다르기 때문에 new와 delete를 사용하는 방법도 다르다. 따라서 single object와 array는   new    delete  를 사용하는 방법이 서로 다르며, 이를 뒤섞어 쓰면 안된다.
  • 이런 차이점 때문에, 클래스 설계 시 어떤 클래스가 동적 할당한 메모리를 가르키는 포인터를 멤버로 가지면서 여러 버전의 constructor를 제공한다면, 모든 constructor가 해당 포인터를 초기화하는데 모두 같은 형태의   new   를 사용하도록 주의해야 한다.
  •   typedef  를 사용할 때도 주의해야 한다. 예를 들어, array에 typedef를 사용하면 사용자는 typedef 된 자료형이 array인지 모르기 때문에 별 생각없이   new  -  delete  를 사용할 수 있다. 이 경우,   new[]    delete  를 같이 사용하는 것 같다.



Summary

  • If you use [] in a   new  expression, you must use [] in the corresponding   delete  expression, If you don't use [] in a   new  expression, you mustn't use [] in the corresponding   delete  expression.

Reference

  • Effective C++ by Scott Meyers