2020의 게시물 표시

구글 C++ 코딩 스타일 가이드

github io 링크 : https://google.github.io/styleguide/cppguide.html#Namespaces

[Effective C++] new 및 delete 를 작성할 때 따라야 할 기존의 관례를 잘 알아 두자

항목 51 : new 및 delete 를 작성할 때 따라야 할 기존의 관례를 잘 알아 두자

[Effective C++] new 및 delete 를 언제 바꿔야 좋은 소리를 들을지를 파악해 두자

항목 50 : new 및 delete 를 언제 바꿔야 좋은 소리를 들을지를 파악해 두자

[Effective C++] new 처리자의 동작 원리를 제대로 이해하자

항목 49 : new 처리자의 동작 원리를 제대로 이해하자

[Effective C++] 템플릿 메타 프로그래밍 하지 않겠는가

항목 48 : 템플릿 메타 프로그래밍 하지 않겠는가

[Effective C++] 타입에 대한 정보가 필요하다면 특성정보 클래스를 사용하자

항목 47 : 타입에 대한 정보가 필요하다면 특성정보 클래스를 사용하자

[Effective C++] 타입 변환이 바람직할 경우에는 비멤버 함수를 클래스 템플릿 안에 정의해 두자

항목 46 : 타입 변환이 바람직할 경우에는 비멤버 함수를 클래스 템플릿 안에 정의해 두자

[Effective C++] "호환되는 모든 타입"을 받아들이는 데는 멤버 함수 템플릿이 직방!

항목 45 : "호환되는 모든 타입"을 받아들이는 데는 멤버 함수 템플릿이 직방!

[Effective C++] 매개변수에 독립적인 코드는 템플릿으로부터 분리시키자

항목 44 : 매개변수에 독립적인 코드는 템플릿으로부터 분리시키자

[Effective C++] 템플릿으로 만들어진 기본 클래스 안의 이름에 접근하는 방법을 알아두자

항목 43: 템플릿으로 만들어진 기본 클래스 안의 이름에 접근하는 방법을 알아두자

[Effective C++] typename 의 두 가지 의미를 제대로 파악하자

항목 42 : typename 의 두 가지 의미를 제대로 파악하자

[Effective C++] 템플릿 프로그래밍의 천릿길도 암시적 인터페이스와 컴파일 타임 다형성부터

항목 41 : 템플릿 프로그래밍의 천릿길도 암시적 인터페이스와 컴파일 타임 다형성부터

[Effective C++] 다중상속은 심사숙고해서 사용하자

항목 40 : 다중상속은 심사숙고해서 사용하자

[Effective C++] private 상속은 심사숙고해서 구사하자

항목 39 :  private 상속은 심사숙고해서 구사하자

[Effective C++] "has-a" 혹은 "is-implemented in terms of"(~는 ~를 써서 구현됨)를 모형화할 때는 객체 합성을 사용하자

항목 38 :  "has-a" 혹은 "is-implemented in terms of"(~는 ~를 써서 구현됨)를 모형화할 때는 객체 합성을 사용하자 소프트웨어 개발에서 영역(domain)은 두 가지로 나뉜다. 사람, 이동수단 등 실제 사물을 본 따서 만든 객체를 응용 영역(application domain), 버퍼, 뮤텍스, 탐색 트리 등 순수하게 시스템 구현만을 위한 인공물들을 구현 영역(implementation domain)에 속해있다고 부른다. 여기서 객체 합성이 응용 영역의 객체들 사이에서 일어나면 has-a 관계이다. 반면 구현 영역에서 일어나면 그 객체 합성의 의미는 ( is-implemented-in-terms-of ) 관계를 나타낸다. 써서 구현되는 관계 (is implemented in terms of) 형태의 설계 -> 특정 파생클래스와 기반클래스가 is-a 관계가 아니지만 , 파생클래스는 기반 클래스의 기능을 활용해서 구현된 것 참조 :  https://mokga.tistory.com/121

[Effective C++] 어떤 함수에 대해서도 상속받은 기본 매개변수 값은 절대로 재정의하지 말자

항목 37 : 어떤 함수에 대해서도 상속받은 기본 매개변수 값은 절대로 재정의하지 말자

[Effective C++] 가상 함수 대신 쓸 것들도 대신 생각해 두는 자세를 시시때때로 길러 두자

항목 35 : 가상 함수 대신 쓸 것들도 대신 생각해 두는 자세를 시시때때로 길러 두자

[Effective C++] 인터페이스 상속과 구현 상속의 차이를 제대로 파악하고 구별하자

항목 34 : 인터페이스 상속과 구현 상속의 차이를 제대로 파악하고 구별하자 . 인터페이스는 외부에서 해당 객체의 동작을 명령을 내리는 버튼과 같고 , 구현이란 특정 명령에 의해 어떻게 동작할지 나타내는 것 . 두 가지는 분명히 다르며 클래스 상속 관계를 설계할 때도 유념해야 할 것 순수 가상 함수를 선언하는 목적은 파생 클래스에게 함수의 인터페이스만을 물려주려는 것입니다 . 단순 가상 함수를 선언하는 목적은 파생 클래스로 하여금 함수의 인터페이스뿐만 아니라 그 함수의 기본 구현도 물려받게 하자는 것입니다 . 비가상 함수를 선언하는 목적은 파생 클래스가 함수 인터페이스와 더불어 그 함수의 필수적인 구현 (mandatory implementation) 을 물려받게 하는 것입니다 . 순수 가상 함수에도 정의를 제공할 수 있다 . 즉 순수 가상함수에도 기본 구현을 달아서 상속시킬 수 있다는 것 . 판단에 따라 인터페이스만을 상속시켜도 되고 , 인터페이스와 기본 구현을 함께 상속시킬 수도 있으며 , 아니면 인터페이스와 필수 구현을 상속시킬 수 있는 것입니다 . 클래스를 설계할 때 가장 기본적인 실수 2 개 : 모든 멤버 함수를 비가상 함수로 선언하는 것 . ( 소멸자 부분이 골칫거리가 될 수 있다 ), 혹은 모든 멤버 함수를 가상함수로 선언하는 것 . 참조 :  https://www.ikpil.com/485

[Effective C++] 상속된 이름을 숨기는 일을 피하자

항목 33: 상속된 이름을 숨기는 일을 피하자

[Effective C++] 파일 사이의 컴파일 의존성을 최대로 줄이자

항목 31 : 파일 사이의 컴파일 의존성을 최대로 줄이자

[Effective C++] 인라인 함수는 미주알고주알 따져서 이해해 두자

항목 30 : 인라인 함수는 미주알고주알 따져서 이해해 두자

[Effective C++] 예외 안전성이 확보되는 그날 위해 싸우고 또 싸우자

항목 29 : 예외 안전성이 확보되는 그날 위해 싸우고 또 싸우자

[Effective C++] 내부에서 사용하는 객체에 대한 '핸들'을 반환하는 코드는 되도록 피하자

항목 28 : 내부에서 사용하는 객체에 대한 '핸들'을 반환하는 코드는 되도록 피하자

[Effective C++] 캐스팅은 절약, 또 절약! 잊지 말자

항목 27 : 캐스팅은 절약, 또 절약! 잊지 말자

[Effective C++] 변수 정의는 늦출 수 있는 데까지 늦추는 근성을 발휘하자

항목 26 : 변수 정의는 늦출 수 있는 데까지 늦추는 근성을 발휘하자

[Effective C++] 예외를 던지지 않는 swap에 대한 지원도 생각해 보자

항목 25 : 예외를 던지지 않는 swap에 대한 지원도 생각해 보자 참조 :  https://wikidocs.net/652

[Effective C++] 타입 변환이 '모든 매개변수'에 대해 적용되어야 한다면 비멤버 함수를 선언하자

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

[Effective C++] 멤버 함수보다는 비멤버 비프렌드 함수와 더 가까워지자

항목 23 : 멤버 함수보다는 비멤버 비프렌드 함수와 더 가까워지자

[Effective C++] 함수에서 객체를 반환해야 할 경우에 참조자를 반환하려고 들지 말자

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

[Effective C++] '값에 의한 전달' 보다는 '상수객체 참조자에 의한 전달' 방식을 택하는 편이 대개 낫다

항목 20 : '값에 의한 전달' 보다는 '상수객체 참조자에 의한 전달' 방식을 택하는 편이 대개 낫다

클래스 설계는 타입 설계와 똑같이 하자

항목 19 : 클래스 설계는 타입 설계와 똑같이 하자 새로 정의한 타입의 객체 생성 및 소멸은 어떻게 이루어져야 하는가? 객체 초기화는 객체 대입과 어떻게 달라야 하는가? 새로운 타입으로 만든 객체가 값에 의해 전달되는 경우에 어떤 의미를 줄 것인가? (보통 이쪽은 복사생성자가 관여한다) 새로운 타입이 가질 수 있는 적법한 값에 대한 제약은 무엇으로 잡을 것인가? 기존의 클래스 상속 계통망(inheritance graph)에 맞출 것인가? 어떤 종류의 타입 변환을 허용할 것인가? 어떤 연산자와 함수를 두어야 의미가 있을까? 표준 함수들 중 어떤 것을 허용하지 말 것인가? 새로운 타입의 멤버에 대한 접근권한을 어느 쪽에 줄 것인가? '선언되지 않은 인터페이스'로 무엇을 둘 것인가? 새로 만드는 타입이 얼마나 일반적인가? 정말로 꼭 필요한 타입인가? 참조 :  https://kkojabee.tistory.com/entry/Effective-C-Item-19-Treat-class-design-as-type-design

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

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

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

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

new 및 delete를 사용할 때는 형태를 반드시 맞추자

항목 16 : new 및 delete를 사용할 때는 형태를 반드시 맞추자

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

항목 14 : 자원 관리 클래스에서 관리되는 자원은 외부에서 접근할 수 있도록 하자

[C++] 우측값 레퍼런스를 어셈블리로 보면??

이미지
prvalue 와 xvalue 의 차이점이 잘 이해가 안되서 살짝 공부해보기로 우측값은 실체가 없는 값이라는 설명을 들은 적이 있지만, 컴파일러의 입장에서는 다른 듯 하다. 7 번째 라인을 보면 스택 메모리의  ebp-78h 위치에 (ebp 는 스택의 시작 주소, 즉 시작지점에서 78번째 아래 있는 부분) 5 값을 저장해두고 있으며, 해당 부분의 주소를 우측값 레퍼런스에 넘겨주고 있다. 우측값 참조되는 값은 분명 메모리 상에 존재하지만 그것을 프로그래머는 알 수 없는 셈 우측값 레퍼런스와 관련해서 빼놓을 수 없는 std::move 명령어는 어떨까. 디스어셈블리로 본다면 그저 넘겨받은 인자의 실 주소값을 그대로 넘겨주고 있다. 사실상 타입변환의 의미만 존재하고 메모리 상에서는 아무 일도 없다.  다시 생각해본다면 prvalue, xvalue 의 차이점을 이렇게 볼 수 있을 것 같다.  전체 rvalue 부류에서 prvalue는 프로그래머 입장에서 그 실체 혹은 메모리의 어디에 있는지 확실히 파악할 수 없는 값.  (리터럴 Int, Char, 값 타입을 반환하는 함수의 반환값, 특정 연산의 결과로 임시로 만들어진 값 등)  마찬가지로 rvalue 에서 xvalue 란 프로그래머 입장에서 그 실체에 대해 알고 잆는 값 {    int a = 1;    int&& rv = std::move(a); // 우측값인 동시에 우리는 a 에 대해 알고 있다. }  참조 :  https://stackoverflow.com/questions/36827900/what-makes-moving-objects-faster-than-copying https://www.learncpp.com/cpp-tutorial/15-3-move-constructors-and-move-assignment/

컴파일러 Copy Elision

참조 :  https://kldp.org/node/160274 https://jacking75.github.io/cpp_copy_elision/

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

항목 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; //기본 클래스 포인터를 활용해서 메모리 반환 }