막연하게 리소스중 하나라고 생각하면서 사용했던 handle의 개념을 정리해보면, 핸들은 "운영체제 내부에 있는 리소스의 주소를 유니크한 정수로 치환한 값"이다. 운영체제의 리소스를 정수로 치환하는 이유는 응용프로그램에서 운영체제의 리소스를 직접 사용하는 것을 막기 위함이다.(운영체제의 리소스를 직접 사용하는 케이스외에도 프레임워크나 서비스등의 자원을 직접 사용하지 못하도록 핸들의 개념을 광범위 하게 사용하는 경우도 있는것 같다.)응용프로그램이 운영체제의 리소스를 직접 사용할경우 치명적인 오류나 보안상 취약하기 때문이다.(이래서 메모리를 user영역과 kernel영역으로 나누어서 사용한다.) 그래서 Handle은 응용 프로그램과 운영체제 사이의 다리역할을 해주는 매개체로 보면 된다. 운영체제의 리소스를 사..
멀티 스레드 환경에서 공유자원에 대한 접근제어를 위해 뮤텍스를 사용한다. 뮤텍스는 반드시 lock - unlock 짝으로 사용 되어야한다.그러나 짝으로 사용 되어도 개발자의 실수로 인해(조기 리턴 등) 문제를 일으킬 수 있다. 이러한 귀찮은 문제들을 한번에 해결해주는 것이 바로 lock_guard 클래스이다.lock_guard는 RAII 스타일로 구현되어 있기 때문에 자원이 할당 되면 mutex 객체를 이용하여 lock을 하고 블록을 벗어나면 자원이 해제 되면서 unlock을 한다. Defined in header template class lock_guard; Ex) int sum = 0;mutex mtx_lock; void func1(int val){ for(int i=0;i
c++는 비관리 코드(unmanaged code)이기 때문에 개발자가 메모리관리를 전부 해줘야한다. 즉, 동적으로 할당 된 객체는 메모리 할당-회수를 항상 페어로 생각해야 한다.그러나 코드의 양이 커지다보면 예상치 못한 부분에서 객체의 메모리를 회수하지 못함으로인해 메모리 누수가 발생하기도 한다. java나 c#같은 언어에서는 GC가 관리해주지만 c++는 그렇지 못하기 때문에 smart pointer가 그 기능을 대신한다.memory헤더 안에 선언되어 있으며 c++11부터 사용 가능하다. smart pointer중 shared_ptr의 동작 원리는 참조 카운팅 방식이다. 즉, 객체를 참조할때마다 카운트가 올라가고 그 카운트가 0이 되는 순간 객체를 delete 시킨다. 이러한 기능을 사용하면 개발자가 굳..
기존에 작성된 코드나 라이브러리에서 제공하는 클래스를 상속해서 사용할 때 주의 할 점이 있다. 바로 가상소멸자의 유무이다. 이번에 공부를 하면서 알게된 사실은 클래스를 만들 때 소멸자를 가상으로 만들지 않은 것은 그 클래스를 기본(Base)클래스로 사용하지 말라는 뜻을 내포한다는 것이다.대표적인 예로 string타입, STL의 컨테이너 타입이 있다. 일단 기본클래스에 가상 소멸자로 선언되어 있지 않으면 어떤 문제가 생기는지 생각해볼 필요가 있다.다형성을 통해 기본클래스의 포인터로 파생클래스를 제어하는 경우 파생클래스의 소멸자가 호출되지 않는 문제가 발생한다.(virtual이 아니기 때문에 가상 함수 테이블이 생성되지 않아서) 아래의 코드는 메모리릭이 발생하는 코드이다.[문제 코드]class Base{pu..
c++에서 객체 생성시 사용자가 class에 정의하지 않았어도 기본적으로 만들어지는 함수들이 있다. 바로 기본 생성자, 복사 생성자, 복사 대입 연산자, 소멸자이다. class Test{ };처럼 빈 클래스를 만들어도 컴파일러에 의해 아래처럼 코드가 생성 된다. class Test{ private: public: Test(){}//기본 생성자 Test(const Test& copy){}//기본 복사 연산자 ~Test(){}//기본 소멸자 Test& operator=(const Test& assign){ return *this; }//기본 대입 연산자 }; 그런데 이러한 컴파일러에 의해 생성되는 코드들은 가끔 불필요할때가 있다.그래서 프로그램내에서 내가 설계한 클래스가 오직 하나만 생성되는 경우(싱글톤) ..
객체가 생성할될 때 가장 먼저 수행되는 것은 생성자이다. 생성되는 객체가 멤버변수를 갖고있다면(거의 대부분) 반드시 생성자에서 멤버변수들을 초기화 해주어야 한다.그런데 이러한 값들을 초기화 할 때도 보다 더 효율적인 방법이 존재한다. 바로 생성자 초기화 리스트를 사용하는 것이다. class PhoneBook{ private: std::string name; std::string phoneNum; int age; PhoneBook class가 있을 때 생성자안에서 다음과 같이 대입연산을 통해서 초기화를 진행하기 보다는 PhoneBook(const std::string& name, const std::string& phoneNum, const int age){ this->name = name; this->p..
c/c++에서 자주 사용 되는 #define 주로 간단한 함수나 고정 된 값이나 고정된 문자열을 만들때 사용 된다.그러나 #define은 다음과 같은 단점이 존재한다. 1. 컴파일 후 기호 테이블에 들어가지 않기 때문에 디버깅의 어려움2. 매크로함수의 경우 의도하지 않은 결과가 나올 수 있음3. 타입 안전성이 떨어짐 따라서 가능하다면 #define을 지양하고 다음과 같은 방법으로 코드를 작성하는게 좋다. #define TEST "TEST" 을 아래와 같이 변경해서 사용한다.const char * const Test = "TEST";const std::string StringTest = "TEST"; #define MAX 100을 아래와 같이 변경해서 사용한다.1.const int Max = 100;2.e..
학교 수업을 들을 때 "데몬 프로세스"라는 단어에 대해서 많이 들어봤지만 항상 궁금했던 점은 백그라운드에서 실행하는(UI)가 없는 프로세스와 도대체 무슨 차이가 있는거지 라는 궁금증이 있었다. 위키에 나온 데몬의 정의를 살펴보면 멀티태스킹 운영 체제에서 데몬(daemon, 발음: 데이먼/'deɪmən/ 또는 디먼 /'dimən/[1])은 사용자가 직접적으로 제어하지 않고, 백그라운드에서 돌면서 여러 작업을 하는 프로그램을 말한다. 시스템 로그를 남기는 syslogd처럼 보통 데몬을 뜻하는 ‘d’를 이름 끝에 달고 있으며, 일반적으로 프로세스로 실행된다.데몬은 대개 부모 프로세스를 갖지 않으며, 즉 PPID가 1이며, 따라서 프로세스 트리에서 init 바로 아래에 위치한다. 데몬이 되는 방법은 일반적으로 ..
대부분 GUI를 사용하는 앱들은 Event-Driven Architecture를 사용하고 있다. Event-Driven 방식은 메인루프에서 이벤트(터치,타임아웃 등)를 받아들이고 이벤트가 발생하면 등록된 핸들러를 이용해서 이벤트 처리 결과를 사용자에게 전달한다. 보통 메인루프는 한번의 iteration(?또는 사이클)을 돌면서 이벤트를 확인,처리한 뒤 idle상태로 들어간다.GNOME에서 만든 라이브러리 glib에서 main loop기능을 제공한다. glib의 g_main_loop를 사용하기 위해서는 우선 $ pkg-config --list-alllibecpg libecpg - PostgreSQL libecpg librarylibpq libpq - PostgreSQL libpq librarygio-uni..
리눅스 환경에서 강건성(robustness)테스트나 디버깅을 진행하다보면 여러가지 오류로인해 프로그램이 종료된다. 이 때 코어덤프가 있으면 디버깅에 유용하지만 로그만 남아 있는 경우도 있다. 이럴때 단서가 되는 부분이 시그널인 것 같다. 그래서 시그널에 대해서 다시한번 상기시켜보려고 한다.(사실 주로 발생하는 시그널은 SIGABRT,SIGKILL,SIGPIPE,SIGSEGV 정도이다.) 시그널의 정의를 보면 시그널은 소프트웨어 인터럽트로, 프로세스에 어떤 이벤트가 발생했음을 알리는 간단한 비동기 메세지이다.인터럽트는 크게 하드웨어 인터럽트와 소프트웨어 인터럽트로 구분된다. 하드웨어 인터럽트는 외부에서 전기적 신호가 발생(이벤트)했을때를 말하고 소프트웨어 인터럽트는 CPU가 연산중에 어떠한 조건에 맞는 이..