반응형

C++ 73

C++ 클래스 함수 간접 호출 : mem_fn, bind, bind_front

C++에서 클래스 함수를 간접적으로 호출할 수 있는 방식 중 mem_fn, bind, bind_front를 아래 예제로 살펴보도록 하겠습니다. #include #include using namespace std; class test_class_fn { public: int add(int a, int b) { return a + b; } auto get_func_mem_fn() { return mem_fn(&test_class_fn::add); } function get_func_bind() { return bind(&test_class_fn::add, this, std::placeholders::_1, std::placeholders::_2); } function get_func_bind_front() ..

C++ 프로그래밍 2021.12.11

C++ 전역 객체 혹은 정적 객체 간의 생성 및 소멸 순서 문제

C++에서 전역 객체 혹은 정적 객체들의 생성과 소멸 순서는 따로 규칙이 정해져 있지 않습니다. C++ 전역 혹은 정적 객체 생성에 관해서 정해져 있는 것은 초기화 이전에 0으로 초기화 된다는 것 뿐입니다. 그 외에 메인의 첫 문장 실행 전에 지역 변수가 아닌 정적 변수가 초기화될 것인지 여부는 컴파일 구현에 따라 틀립니다. 이런 세세한 것을 알아야 하는 이유는 전역 혹은 정적 객체간에 직접적 혹은 간접적으로 참조를 하는 경우에 문제가 생길 수 있기 때문입니다. 한 예로 전역 변수 A가 정적 변수 B를 호출하는데 생성 및 초기화 순서에 따라 전역 변수 A는 초기화 되지 않는 정적 변수 B를 호출할 수 있습니다. 이런 경우 프로그램이 멈추거나 잘못된 값을 가지는 알 수 없는 상황이 발생하게 됩니다. 또 다..

C++ 프로그래밍 2021.12.09

쓰레드 풀에서 CPU 사용량 줄이기

쓰레드풀에서 흔하게 사용되는 방법이 워커 쓰레드를 N개 생성하여 놓고 공유하는 작업 큐에서 데이터를 받아와 워커 쓰레드에서 실행하는 방법입니다. 이 때 작업 큐가 비었을 때 워커 쓰레드를 재워주는 처리를 해주지 않으면 CPU 사용량이 올라가게 됩니다. sleep을 해주는 것도 재운 시간에 작업 큐에 데이터가 들어왔다면 그 만큼 워커 쓰레드에서 늦게 실행하게 되어 재우는 시간도 민감하게 설정하여야 합니다. 이 때 사용할 수 있는 방법이 작업 큐에 조건 락(conditional lock)을 사용하는 것입니다. 이 방법을 바탕으로 작업 큐가 비어 있을 때만 워커 쓰레드를 재우고 작업 큐에 데이터가 들어왔을 때는 깨울 수 있습니다. 이 방법은 워커 쓰레드의 사용성은 높이면서 CPU 사용량을 줄이는 방법입니다. ..

C++ using namespace를 헤더 파일에 사용하지 말자

using namespace는 특정 네임스페이스의 클래스들을 네임스페이스 참조 없이 사용하기 위하여 흔히 사용하는 문법입니다. 흔한 예로는 STL을 사용하기 위하여 사용하는 using namespace std;와 같은 것이 있습니다. 네임스페이스를 생략하는 편의성 때문에 헤더에 using namespace를 사용하니 아래와 같은 문제가 발생하였습니다. 현재 개발 중인 프로젝트에서 사용하는 라이브러리들이 STL, Boost, MongoCXX, Cybos API등인데 같은 클래스이름 때문에 충돌이 발생하였습니다. 헤더 파일에서야 원인을 파악하고 클래스 앞에 네임스페이스를 넣어줘서 충돌을 막아줄 수 있었습니다. 그런데 cpp파일에서는 using namespace 구문이 있는 헤더가 포함되니 포함 순서에 따라서..

C++ 프로그래밍 2021.12.01

C++ 람다에서 참조 값과 복사 값 동시에 사용하기

C++ 람다는 C++ 특성상 복사와 참조 그리고 객체의 생명주기 등을 고려해야 메모리 관련 버그가 없습니다. 람다에서 참조만 사용할 경우 프로그램에 따라서 참조하는 값이 메모리에서 해제되면 메모리 관련 버그가 발생하게 됩니다. 이럴 경우 복사를 같이 사용해야 합니다. 해당 설명에 대한 아래 예를 살펴보겠습니다. 아래 코드는 해당 상황을 보여주기 위한 예제인 관계로 현실적인 사용과는 조금 다를 수 있으니 참고 바랍니다. #include #include #include using namespace std; struct std_15_sub { public: int value = 1; }; class std_15A { private: void print_value(int value) { cout value]의 ..

C++ 프로그래밍 2021.11.29

std::chrono::steady_clock 관련 종합 예제

std::chrono::steady_clock을 사용할 일이 있어서 이리 저리 조사를 하며 만들어본 예제입니다. 예제에는 지나간 시간 체크, 시간 차 duration에 시간 더하기, 현재 구한 시간에 시간 더하기, duration과 long long간의 형변환, 시간차를 나타내는 duration 시간 이쁘게 보여주기 등등이 포함되어 있습니다. 예제 소스는 아래와 같습니다. #include #include #include #include using namespace std; int main(int argc, char* argv[]) { // 예제 #1: 지나간 시간을 체크합니다. auto now1 = std::chrono::steady_clock::now(); this_thread::sleep_for(st..

C++ 프로그래밍 2021.11.22

C++ boost json 구조체와 json 문자열간 변환 예제

boost json라이브러리를 사용하면 구조체와 json문자열 간의 상호 변환이 간단합니다. 여기서는 간단한 변환 예를 살펴보며 사용법을 알아보겠습니다. 우선 아래와 같은 간단한 예로 살펴보겠습니다. #include #include #include using namespace std; struct user { int id; string name; bool login; }; void tag_invoke(boost::json::value_from_tag, boost::json::value& jv, user const& u) { jv = { {"id", u.id}, {"name", u.name}, {"login", u.login} }; } user tag_invoke(boost::json::value_to_t..

[MongoDB] C/C++ BSON 한글 문자열 입출력

MongoDB는 BSON을 사용합니다. BSON에서 문자열은 UTF-8을 사용합니다. UTF-8과 ANSI의 관계상 영문만 사용한다면 별도의 변환은 필요 없습니다. 그러나 일반적으로 사용하는 한글과 같은 멀티 바이트 문자열이나 유니코드 문자열은 별도로 UTF-8로 인코딩하여야 합니다. 또한 MongoDB에 저장된 문자열을 사용하기 위하여 UTF-8문자열을 한글과 같은 멀티 바이트 문자열이나 유니코드로 디코딩해야 합니다. 참고로 MongoDB C/C++ Driver API에 한글과 같은 멀티 바이트 문자열을 인자로 넣으면 바이트 수가 틀리다는 류의 에러가 나면서 API가 실행되지 않습니다. C/C++에서 한글과 같은 멀티바이트 문자열을 UTF-8로 변환하는 방법은 아래와 같습니다. 우선, boost 라이브..

boost locale을 이용한 C++에서의 Multi Byte와 UTF8간의 문자열 변환

영문만 있는 경우는 문자열은 C/C++에서 UTF-8로 별도의 변환을 필요로 하지 않습니다. 하지만 한글과 같이 멀티 바이트를 사용하는 경우는 별도로 UTF-8로 인코딩 및 디코딩을 해주어야 합니다. 이런 경우 사용할 수 있는 라이브러리가 boost local입니다. 간단한 Multi Byte와 UTF8간의 문자열 변환 예제는 아래와 같습니다. #include #include #include using namespace std; int main(int argc, char* argv[]) { string str = "{\"name\": {\"first\":\"그레이스\", \"last\":\"Hopper\"}}"; cout

동적 라이브러리(DLL)를 사용할 것인가? 아니면 정적 라이브러리(LIB)를 사용할 것인가?

일정 규모 이상의 프로그램을 만들다보면 공통적으로 참조하는 공통 라이브러리를 만들고 여러 프로그램에서 참조하게 하는 경우가 종종 있습니다. 공통 라이브러리는 프로그램에 내용이 포함되는 정적 라이브러리와 DLL, SO등의 별도 확장자로 필요에 따라 로딩되어 참조되는 동적 라이브러리가 있습니다. C++이나 기타 언어의 서적을 보게 되면 실행 파일이 참조하는 라이브러리로 보통은 동적 라이브러리를 많이 추천합니다. 동적 라이브러리의 장점은 아래와 같습니다. 첫째로 여러 프로그램이 참조하더라도 라이브러리 사용 메모리는 하나의 프로그램의 사용에 필요한 만큼만 필요합니다. 덕분에 메모리는 여러개의 프로그램에서 참조하더라도 (사용 프로그램 수 N개 - 1) * 사용 메모리 크기 만큼 절약하게 됩니다. 둘째로 라이브러리..

C++ 프로그래밍 2021.11.18

C++ boost 메모리풀 강좌 #5: boost 메모리풀 할당자를 적용하여 STL 컬렉션의 성능 향상시키기

STL 컬렉션은 템플릿 지정자를 이용하여 메모리 할당자를 설정할 수 있습니다. 참고로 메모리 할당자란 컬렉션에 요소에 대해서 메모리 new / delete하는 객체를 말합니다. STL 컬렉션에 메모리 할당자를 메모리풀을 사용하도록 하여 성능을 향상 시킬 수 있습니다. boost에는 이 STL 컬렉션 관련 메모리 풀 지원 할당자가 pool_allocator와 fast_pool_allocator이 있습니다. 두 할당자 모두 어느 STL 컬렉션에나 사용할 수 있습니다. 특징적으로 pool_allocator는 vector처럼 연속된 메모리 할당 및 해제가 일어나는 STL 컬렉션에서 성능이 좋습니다. fast_pool_allocator는 list처럼 단일 메모리 할당 및 해제가 일어나는 STL 컬렉션에서 성능이 ..

강좌 2021.11.15

C++ boost 메모리풀 강좌 #4: object_pool 클래스를 이용하여 new 재정의 없이 일반 클래스에 메모리풀 적용하기

object_pool은 pool의 클래스 할당 및 해제 버전으로 보면 이해하기 쉽습니다. pool과 사용법이 유사한데 틀린점은 construct와 destory 함수를 이용하여 할당 및 해제를 한다는 점입니다. 또한 construct 함수를 호출할 때 생성 인자를 넣어서 생성할 수도 있습니다. 단, 아쉽게도 생성인자는 3개까지 지원합니다. new 재정의로 메모리 풀을 적용하지 않은 클래스에 대하여 생성시점에서 메모리풀을 사용하기에 좋습니다. 간단한 예를 살펴보도록 하겠습니다. #include #include using namespace std; class test_mpa2 { private: char test_[256]; public: test_mpa2(const char* str) { strcpy_s(..

강좌 2021.11.14

C++ boost 메모리풀 강좌 #3: singleton_pool 클래스를 이용하여 일반 클래스에 메모리풀 적용하기

singleton_pool 클래스도 기본적으로 이전에 설명한 pool과 비슷합니다. 이 클래스는 템플릿 주요 인자로 할당 크기를 구분하는 태그 인자와 할당 크기를 받습니다. 태크 인자와 할당 크기라는 인자 특성 때문에 일반 클래스에 operator new / delete를 재정하여 적용하기에 쉽습니다. 이 외에 singleton_pool은 기본적으로 멀티쓰레드에서 안전합니다. 싱글쓰레드에서 사용할 때는 성능을 올리기 위하여 mutex 인자 부분에 boost::details::pool::null_mutex을 넣어주면 좋습니다. 간단한 사용법 예를 살펴보겠습니다. #include #include using namespace std; template class memory_pool_allo..

강좌 2021.11.13

C++ boost 메모리풀 강좌 #2: pool 클래스를 이용하여 버퍼에 메모리풀 적용하기

boost 메모리풀 관련 클래스 중 pool은 메모리풀을 활용하여 C 스타일로 메모리를 할당 및 해제할 때 사용할 수 있는 클래스입니다. 이런 특성을 가진 관계로 C++에서 C스타일로 메모리를 할당 및 해제하는 버퍼에 적용하기 좋습니다. 이 클래스를 버퍼에 활용하면 메모리풀이 적용되어 성능 향상에 좋습니다. 간단히 아래 예제를 통하여 살펴보겠습니다. #include #include using namespace std; int main(int argc, char* argv[]) { boost::pool pool(sizeof(char) * 32); char* test = (char*)pool.malloc(); strcpy_s(test, sizeof(char) * 32, "test test test test"..

강좌 2021.11.12
반응형