반응형

SW/C++ 87

C : 간단하고 사용하기 쉬운 JSON Parser

오픈 소스 C 라이브러리인 멜론의 JSON 파서를 살펴보고, 그 특징을 잘 알려진 cJSON과 비교하여 차이점과 유사점을 이해합니다. 오픈 소스 C 라이브러리 멜론의 JSON 파서를 소개합니다. 많은 독자들이 cJSON에 대해 들어보거나 사용해보았을 것이라 생각합니다. 매우 유명한 오픈소스 프로젝트입니다. 이 글에서는 cJSON과 멜론의 JSON 구성요소를 비교하고자 합니다. 인코딩 다음과 같은 JSON을 구축하려고 합니다: { "name": "Awesome 4K", "resolutions": [ { "width": 1280, "height": 720 }, { "width": 1920, "height": 1080 }, { "width": 3840, "height": 2160 } ] } 그럼 먼저 cJSO..

SW/C++ 2023.12.04

C++ : shared_ptr 와 weak_ptr : 개념, 차이, 활용법, 예제, 구현

std::shared_ptr 강한 참조 기반입니다. 강한 참조 카운트를 늘려줍니다. 직접적으로 사용할 수 있습니다. 원시 포인터가 확실히 존재하기 때문입니다. std::weak_ptr 약한 참조 기반입니다. 약한 참조 카운트를 늘려줍니다. 직접적으로 사용할 수 없습니다. lock을 써서 std::shared_ptr가 여전히 존재하는 지 확인해야 합니다. 예제 #pragma once #include #include #include #include #include "MyVector2D.h" using namespace std; namespace samples { class SimpleCache { public: SimpleCache() = default; ~SimpleCache() = default; voi..

SW/C++ 2020.05.10

C++ : weak_ptr : 약한 참조 개념, 사용법, 예제, 구현

약한 참조 약한 참조는 원시 포인터 해제에 영향을 끼치지 않습니다. 약한 참조 카운트는 약한 참조의 수를 저장하는 데 사용됩니다. 약한 참조로 참조되는 개체는 강한 참조 카운트가 0이 될 때 소멸됩니다. 순환 참조 문제의 해결책입니다. #include #include "Persion.h" int main() { std::shared_ptr owner = std::make_shared("pp"); std::weak_ptr weakOwner = owner; return 0; } 약한 포인터로 공유 포인터 만들기 #include #include "Persion.h" int main() { std::shared_ptr owner = std::make_shared("pp"); std::weak_ptr weakOw..

SW/C++ 2020.05.09

C++ : shared_ptr : 개념, 예제, 사용법, 구현

std::shared_ptr #include #include"Vector.h" int main() { std::shared_ptr vector = std::maked_shared(10.f, 30.f); // ... } 두개의 포인터를 소유합니다. 데이터를 가리키는 포인터와 제어 블록을 가리키는 포인터입니다. std::unique_ptr와 달리, 포인터를 다른 std::shared_ptr와 공유할 수 있습니다. 참조 카운팅 기반이라 할 수 있습니다. 원시 포인터는 어떠한 std::shared_ptr에게도 참조되지 않을 때 소멸됩니다. 포인터 재설정하기 std::shared_ptr vector = std::maked_shared(10.f, 30.f); std::shared_ptr copiedVector = ..

SW/C++ 2020.05.08

C++ : 자동 메모리 관리, 가비지 컬렉션, 참조 카운트 : 개념, 관계, 장단점

자동 메모리 관리 std::shared_ptr를 배우기 전에, 자동 메모리 관리에 관해 알아야 합니다. 주로 쓰는 두가지 기법이 있었습니다. 첫번째는 가비지 컬렉션이고, 두번째는 참조 카운팅이 있습니다. 가비지컬렉션은 Java와 C#에서 활용되고 있으며, 참조 카운팅은 Swift와 오브젝트 C에서 지원됩니다. 가비지 컬렉션 보통 트레이싱 가비지 컬렉션을 의미합니다. 메모리 누수를 막으려는 시도에서 나오게 되었습니다. 주기적으로 컬렉션을 실행합니다. 충분한 여유 메모리가 없을 때 컬렉션이 실행됩니다. 스케쥴에 따라 또는 수동으로도 실행 가능합니다. 매 주기마다 GC는 루트를 확인합니다. 즉, 전역 변수, 스택, 레지스터들을 확인합니다. 힙에 있는 개체에 루트를 통해 접근할 수 있는 지 판단합니다. 접근할 ..

SW/C++ 2020.05.07

C++ : unique_ptr : 배스트 프렉티스, 기본 예제, 활용 방법, 동작 방식

std::unique_ptr 포인터 대신 아주 많이 활용되고 있습니다. 직접 메모리 관리하는 것 만큼 빠릅니다. Resource Acquisition is initialization 원칙에 잘 들어맞습니다. 자원 할당은 개체의 수명과 관련되어 있습니다. 생성자에서 new를 하고 소멸자에서 delete를 해주어야하는데 유니크 포인터 멤버 변수가 알아서 동작하여 줍니다. 따라서, 실수하기 어려우며, 다양한 곳에서 활용하여도 좋습니다. 예제 #include #include #include "UsingUniquePointersExample.h" #include "MyVector.h" using namespace std; namespace samples { void UsingUniquePointersExample..

SW/C++ 2020.05.06

C++ : unique_ptr : reset, get, release, move, 복사 : 개념, 예제

reset() int main() { std::unique_ptr vector = std::make_unique(10.f, 30.f); vector.reset(new Vector(20.f, 40.f)); vector.reset(); } 이거 말고 nullptr를 써야할까? vector.reset(); vecotr = nullptr; 두 코드의 의미는 같습니다. nullptr가 reset() 보다 가독성이 더 좋습니다. reset()은 vector가 원시 포인터가 아님을 분명하게 보여줍니다. 따라서, 취향에 맞게 구현하여도 무방하다고 합니다. reset()은 결국 포인터를 교체하는 것을 의미합니다. std::unique_ptr가 재설정 될 떄, 소유하고 있던 원시 포인터는 자동으로 소멸됩니다. get() ..

SW/C++ 2020.05.05

C++ : unique_ptr : 유니크 포인터 개념, 필요성, 장점, 활용법

스마트 포인터 - unique_ptr - shared_ptr - weak_ptr 예시: 포인터 #include "Vector.h" int main () { Vector* myVector = new Vector(10.f, 30.f); // delete myVector; return 0; } 항상 포인터를 생성하는 순간, delete를 구현해주어야 합니다. 하지만 프로그래머들이 가끔 실수를 할 수 있습니다. 더 이상 포인터가 필요하지 않을 때 메모리를 해제해야 합니다. 스마트 포인터를 쓰면 delete를 직접 호출할 필요가 없습니다. 그리고 가비지 컬렉션보다 빨라집니다. unique_ptr #include #include "Vector.h" int main() { std::unique_ptr myVector..

SW/C++ 2020.05.04

C++ : std::array : 개념, 장점, 단점, 필요성, 활용성, 예제, 구현

std::array 요소 수를 기억하지 않습니다. 단순히 C 스타일 배열을 추상화한 것이라 생각하면 좋습니다. 요소 수를 기억하지 못하므로 std::array가 아쉬울 수 있습니다. 아마 std::algorithm을 쓸 수 있고, 반복자를 쓸 수 있어서 나온 것일까요. 현재 사이즈를 접근할 필요가 없고, 고정형 크기의 배열이 필요하다면 선택지로 사용할 수 있는 컨테이너라는 생각이 들었습니다. 다만 프로젝트에서 그러한 경우가 그렇게 많지 않을 것으로 생각이 되었는데, 만약 그러한 상황이어도 굳이, 익숙하지 않은 array를 꺼내지 않아도 얼마든지 다른 방법으로도 충분히 해결 가능합니다. 이러한 컨테이너가 있다는 것을 기억해두고 좋은 기회가 오면 활용해보는 것도 좋을 것 같습니다. #include int m..

SW/C++ 2020.05.03

C++ : unordered_set : 개념, 차이점, 장점, 예제, 구현

set 자동 정렬되는 컨테이너입니다. 키들을 저장하고, 이진 탐색 트리를 기반으로 합니다. 탐색 시간은 O( log n ) 입니다. 삽입과 제거가 빈번해지면 느립니다. undorderd_set std::map과 동일한 문제로 나오게 되었습니다. 자동 정렬되지 않는 set이라고 생각하면 됩니다. 해쉬 테이블 기반으로 합니다. 탐색시간이 O(1) 이며 최악의 경우 O(n) 입니다. 버킷 때문에 메모리 사용량이 증가할 수 있습니다. #include #include #include #include #include "SpeedTestExample.h" using namespace std; namespace samples { void SpeedTestExample() { // RUN THIS EXAMPLE IN R..

SW/C++ 2020.05.01

C++ : unordered_map : 개념, 장점, 예제, 구현

unordered_map std::map은 자동으로 정렬되는 컨테이너입니다. 그래서 요서 삽입, 제거가 빈번할 경우에는 성능이 저하됩니다. 그래서 그부분을 해결하기 위해 나온 것이 unordered_map입니다. #include #include #include int main() { std::unordered_map scores; scores["nana"] = 60; scores["mocha"] = 70; scores["coco"] = 100; for (auto it = scores.begin(); it != scores.end(); ++it) { std::cout first

SW/C++ 2020.04.30

C++ : 람다식 : 장점, 단점, 배스트 프랙티스, 예제, 구현

람다식의 장점 간단한 함수를 빠르게 만들어 구현할 수 있습니다. 람다식의 단점 디버깅하기 힘들어질 수 있습니다. 함수 재사용성이 낮아집니다. 사람들은 보통 함수를 새로 만들기 전에 클래스에 있는 기존 함수를 찾아봅니다. 람다 함수는 눈에 잘 띄지 않아서 못찾을 가능성이 높습니다. 그럼 코드 중복이 발생하게 되는 것입니다. 베스트 프랙티스 기본적으로 이름 있는 함수를 씁니다. 자잘한 함수는 람다로 써도 괜찮습니다. 허나 재사용할 수 있는 함수를 찾기는 어렵습니다. 정렬 함수 처럼 stl 컨테이너에 매개변수로 전달할 함수들도 좋은 후보입니다. qsort()에 함수 포인터 넘겨주기보다는 람다가 확실히 더 좋습니다. #include #include #include "LambdaExpressionsExample...

SW/C++ 2020.04.29

C++ : 람다식 : 개념, 예제, 구성, 방법, 활용법

람다식이란 이름이 없는 함수개체, 내포되는 함수를 의미합니다. []() -> { // body } 람다 식을 품는 법위 안에 있는 변수를 람다 식에 넘겨줄 떄 사용합니다. 캡처의 종류 [] : 비어 있으므로, 캡처하지 않습니다. = : 값에 의한 캡처, 모든 외부 변수를 캡처합니다. 람다 식 안에서 수정할 수는 없습니다. & : 참조에 의한 캡처입니다. 모든 외부 변수를 캡처합니다. : 특정 변수를 값으로 캡처합니다. 람다 식 안에서 수정할 수 없습니다. & : 특정 변수를 참조로 캡처합니다. int main (){ float score1 = 80.f; float score2 = 20.f; auto max = [=](){ return score1 > score2 ? score1 : score2; } st..

SW/C++ 2020.04.28

C++ : constexpr : 개념, 예제, 사용법, 필요성, 장점

constexpr 컴파일 시에 값 평가를 강제하기 위해서 템플릿 메타프로그래밍을 남용하였습니다. 이러지 않아도 컴파일러가 자발적으로 그렇게 해주는 경우도 있긴하였습니다. constexpr가 프로그래머의 의도를 보여주는 더 좋은 방법이라 할 수 있습니다.컴파일 도중에 값을 평가하는 것을 컴파일러에게 알려줍니다. 컴파일러가 컴파일 도중에 변수들을 결정지어 줍니다. 함수는 최대한 노력을 합니다. constexpr int Factorial ( int n){ return n = 1 ? 1 : n * Factorial(n -1); } int main () { int value = 3; int result1 = Factorial(value); constexpr int result2 = Factorial(value);..

SW/C++ 2020.04.27

C++ : 이동대입연산자 : 개념, 예제, 활용방법

이동 대입 연산자 & ::operator=(&&) 이동 생성자와 같은 개념입니다. 다른 개체 멤버 변수들의 소유권을 가져옵니다. 이것도 메모리 재할당을 하지 않습니다. 또 얕은 복사입니다. STL 컨테이너용 이동 문법 C++11 이후로, STL 컨테이너에 이동생성자와 이동 대입이 생겼습니다. 그래서 따로 구현할 필요가 없어졌습니다. rvalue 최적화 새로운 프로그래밍 유행어 중 하나입니다. 이동생성자와 이동 대입 연산자는 유효한 내용입니다. 그러나 포인터 대신 개체 자체를 반환하는 함수에서 rvalue를 반환하는 것은 실제로는 매우 느리다고 합니다. 반환 값 최적화라고 하는 컴파일러 최적화를 깨뜨립니다. 가장 좋은 방법은 기본적으로 그냥 개체를 반환해야 합니다. 더 빠라진다고 입증된 경우에만 함수가 r..

SW/C++ 2020.04.26

C++ : lvalue, rvalue, move, 이동생성자 : 개념, 장점, 필요성

lvalue 단일 식을 넘어 지속되는 개체를 의미합니다. 주소가 있으며, 이름이 있는 변수입니다. const 변수, 배열 변수, 비트 필드, 공용 구조체, 클래스 멤버, 좌측 값 참조로 반환하는 함수 호출, 문자열 리터럴 등을 의미합니다. 대부분 지금까지 익숙한 것들을 lvalue라고 생각하면 됩니다. rvalue lvalue가 아닌 개체라고도 할 수 있습니다. 사용되는 단일 식을 넘어 지속되지 않는 일시적인 값을 의미합니다. 주소가 없는 개체, 리터럴(문자열 리터럴 제외), 참조로 반환하지 않는 함수 호출, i++, i-- 등 기본으로 지원되는 산술식, 논리식, 비교식 등이 있습니다. 추가적으로 람다, 열거형들이 그 예라 할 수 있습니다. C++에서 어떻게 복사를 막을 수 있을까요? rvalue 참조와..

SW/C++ 2020.04.25

C++ : 템플릿 : 특수화, 장점과 단점, 베스트 프랙티스

템플릿 특수화 특정한 템플릿 매개변수를 받로록 템플릿 코드를 커스터마이즈를 할 수 있습니다. std::vector에 좋은 예제가 있습니다. 제너릭한 벡터와 다르게 bool 형은 다르게 구현이 되어 있습니다. 제네릭 템플릿이 어느 형에나 적용되어 있습니다. 단 특정형에 특수화된 템플릿이 있다면, 그 특수화된 템플릿이 적용됩니다. 그러나 자주 사용되지는 않습니다. 하지만 std::vector에서는 bool형에 대한 특수화는 가치가 있습니다. 그 이유는 메모리를 더욱 효율적으로 활용하도록 구성할 수 있기 떄문입니다. 전체 템플릿 특수화 template VAL Power(const VAL value, EXP exponent) {} template float Power(float value, float exp) ..

SW/C++ 2020.04.24
반응형