2월, 2020의 게시물 표시

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

항목 14 : 자원 관리클래스와 복사 동작에 대해 진지하게 고찰하자

자원 관리에는 객체가 그만!

항목 13 : 자원 관리에는 객체가 그만!

객체의 모든 부분을 빠짐없이 복사하자

항목 12 : 객체의 모든 부분을 빠짐없이 복사하자

operator= 에서는 자기대입에 대한 처리가 빠지지 않도로 하자

항목 11 : operator= 에서는 자기대입에 대한 처리가 빠지지 않도로 하자

define, typedef, using (C++)

이펙티브 모던 c++ : typedef 보다는 using 사용하기  https://spikez.tistory.com/271 typedef 와 define 차이점 :  https://aticleworld.com/typedef-vs-define-in-c/  - #define 은 단순 코드 치환이라 컴파일 전후로 내용이 달라진다.  - 단순 치환은 복제된 인자값이 프로그래머가 예상치 못한 동작을 하거나, 타입 체크가 이루어지지 않는 등, 여러 모로 문제를 발생시킬 여지가 있기 때문에 #define 보다는 const, enum, inline 함수 등을 사용하는게 좋다는 조언이 있다.(Effective c++의 내용)  - using, typedef 는 특정 타입에 대한 또 다른 별칭을 지정해 주는 키워드. 컴파일 명령어라 문제가 있다면 컴파일 시점에서 확인 가능  - using 과 typedef 의 경우 using 을 사용할때 읽는 입장에서 가독성이 더 좋다는 의견이 많고  - using 은 템플릿화가 가능한 반면 typedef 는 불가능하다는 차이가 있다.(effective modern c++ 내용)

KMP 알고리즘 링크

KMP( Knuth, Morris, Prett) 알고리즘 배우기 좋은 사이트 링크 소스코드 :  https://github.com/maniaKj/C-_Study/blob/master/KMP.cpp 블로그 개념 정리 https://bowbowbow.tistory.com/6 https://jason9319.tistory.com/130

스크립트형 언어

이미지
먼저 컴파일 언어와 인터프리터 언어에 대해서  컴파일 언어 : 프로그래머가 작성된 코드가 컴파일러를 통해 기계어(0과 1로 이루어진)로 변환된 뒤 구동되는 언어이다. 인터프리터 언어와 비교하자면 프로그램으로서 실행되기 전에 반드시 컴파일되어 실행파일이 생성되어야 한다는 차이점이 있겠다.  대표적인 예시로 c++, java 가 있다.  인터프리터 언어 : 마찬가지로 작성된 코드가 있다면 프로그램이 실행되는 런타임에 한줄씩 기계어로 번역(interpreting)되어 동작한다. 컴파일 언어가 변수 선언 혹은 함수 작성시에 자료형 명확하게 명시해야 하는 규칙이 있는 반면에 인터프리터 언어는 그에 대해서 훨씬 조건이 유연하다. 파이썬 같은 경우는 변수의 자료형을 굳이 작성하지 않아도 잘 동작한다.  이런 점은 인터프리터 언어를 작성하기가 쉽고 배우기도 편하다는 장점이 있지만, 한줄 한줄 씩 런타임에 번역되기 때문에 c++ 같은 컴파일 언어에 비해서는 속도가 느리다는 단점도 존재한다.  예시로는 Python, javascript, PHP 등이 있다. 출처 :  https://brunch.co.kr/@insuk/11 스크립트형 언어는 특정 실행 가능한 프로그램을 작성하는 언어라기 보다는  어떤 프로그램에 대해서 해당 프로그램이 어떤 동작을 할지 명시하는 명령리스트를 작성하는 언어라고 볼 수 있겠다.  위의 사진은 3D 모델링 프로그램 블렌더에서 Python 으로 원숭이 모델을 랜덤생성하는 장면  블렌더3D 가 파이썬으로 작성된 프로그램은 아니지만,  사용자는 파이썬을 사용해서 작성된 명령들을 블렌더3D에 적용이 가능하다.  파이썬은 블렌더3D와 분명 독립적으로 사용되어진다고 볼 수 있다. 또한 블렌더 3D 외부에서 스크립트로 작성된 명령을 응용 프로그램으로 적용할 수 있는 것. 이처럼 스크립트형 언어는 응용 프로그램 외부에서 프...

객체 생성 및 소멸 과정 중에는 절대로 가상 함수를 호출하지 말자

항목 9 :  객체 생성 및 소멸 과정 중에는 절대로 가상 함수를 호출하지 말자 .   기본클래스가 생성되는 시점에 , 파생클래스는 아직 만들어지지 않은 상태다 .  이때 가상함수를 실행하게 되면 파생클래스의 함수는 실행할 수 없는게 당연   소멸자의 경우도 마찬가지 ,  파생클래스가 소멸된 시점에 기본클래스의 소멸자 내부에 가상함수에 있다면 프로그래머가 원하는 동작을 하지 않을 수 있다 . class  Transaction { public :     Transaction()      {          logTransaction();      }      virtual   void  logTransaction()  const  { std::cout  < <   "Transaction"   < <  std::endl; } }; class  BuyTransaction :  public  Transaction { public :      virtual   void  logTransaction()  const  { std::cout  < <   "BuyTransaction"   < <  std::endl;...

소멸자에서는 예외가 빠져나가게 하지 말 것

항목 8 :  소멸자에서는 예외가 빠져나가게 하지 말 것 class Widget { public: ~Widget() {} //소멸자에서 에러가 발생한다고 가정 //c++ 은 예외를 넘기는 소멸자를 좋아하지 않는다 }; void DoSomething () { std::vector<Widget> v( 10 ); //벡터에 담겨진 클래스 객체를 반환할때 그 책임은 벡터에 있다. //만약 벡터의 객체가 소멸될 때 에러가 터진다면?? }   소멸자   안에서   호출된   함수가   예외를   던질   가능성이   있다면 소멸자에서   모두   받아낸   후에   삼켜버리던지 (try/catch  문 ) 프로그램을   끝내든지  해야   한다 . (std::abort())   -  예외를   일으키는   소멸자는   프로그램의   불완전   종료   혹은   미정의   동작의   위험을   내포하고   있기   때문이다 . class DBConnection { public: static DBConnection create(); void close (); //연결을 닫기, 이때 연결이 실패하면 에러 발생 }; class DBConn { public: DBConn(DBConnection target) : db(target) {} ~DBConn() { db.close; //객체 소멸시 db 연결을 닫기, 에러가 발생한다면? } private: DBConnection db; }; void DoSomething2 () ...

다형성을 가진 기본 클래스는 소멸자를 가상 함수로 선언할 것

항목 7 :   다형성을 가진 기본 클래스는 소멸자를 가상 함수로 선언할 것   기반 클래스의 소멸자가 비가상 함수라면, 기반 클래스 포인터에서 delete 명령어로   소멸자를 호출할때 기반클래스의 소멸자는 호출되지만   파생클래스 소멸자는 호출되지 않는다 !!! (클래스의 다형성을 고려한다면 기반클래스에서 소멸자에 virtual 키워드는 필수 )  따라서 std::string 같은 클래스는 따로 가상 소멸자를 가지고 있지 않으니 string 을 상속해서 새로운 파생 클래스를 만드는 것은 위험한 행위.  - 그래도 virtual 키워드를 남용하지는 말자 . 클래스가 다형성을 가질 필요가 없다면 가상 소멸자는 필요가 없다. (가상 함수 테이블 포인터가 생성되면 어찌됐건 클래스 크기는 증가하므로) class TimeKeeper { public: TimeKeeper(); //~TimeKeeper(); //기본 클래스 포인터로 객체를 삭제할 때, 소멸자가 가상함수가 아니라면 //클래스의 기본 클래스 부분만 삭제하고, 파생클래스 부분은 삭제되지 않는다. virtual ~TimeKeeper(); //소멸자에 virtual 키워드를 붙여서 해결 virtual TimeKeeper* getTimeKeeper (); }; class AtomicClock : public TimeKeeper {}; class WaterClock : public TimeKeeper {}; void DoSomething () { AtomicClock ac; TimeKeeper* ptk = ac.getTimeKeeper(); delete ptk; //기본 클래스 포인터를 활용해서 메모리 반환 }