반응형
C++ 코드에서 이름 짓기는 매우 중요한 요소입니다. 변수, 함수, 클래스, 네임스페이스, 매크로, 열거형 등 다양한 요소에 이름을 부여할 때, 일정한 규칙을 따르면 코드를 읽는 이가 의도를 더 쉽게 파악할 수 있습니다. 하지만 네이밍 컨벤션에 대한 스타일 가이드들은 저마다 다른 권장사항을 내놓습니다. 어떤 곳은 함수명을 CamelCase로, 어떤 곳은 snake_case로 쓰라고 하고, 또 다른 곳은 클래스 앞에 C를 붙이는 구시대적 관례를 아직도 유지하기도 합니다.이 글에서는 구글 C++ 스타일 가이드, LLVM 스타일 가이드, 모질라 스타일 가이드 등 다양한 스타일 가이드에서 권장하는 네이밍 컨벤션을 비교하고, 각 스타일의 장단점을 분석합니다. 또한 팀이나 프로젝트 상황에 따라 어떤 네이밍 컨벤션을..
C++ 코드 스타일에서 가장 먼저 부딪히는 문제 중 하나가 바로 들여쓰기(Indentation)입니다. 개발자는 최소한의 수평 정렬을 통해 코드 계층 구조를 표현하는데, 이때 스페이스(space)와 탭(tab) 중 무엇을 사용할지, 기본 들여쓰기 폭은 얼마로 할지, 그리고 라인 길이는 어느 정도로 제한할지를 결정해야 합니다.본 글에서는 대표적인 스타일 가이드(구글 C++ 스타일 가이드, LLVM 스타일 가이드, 모질라 스타일 가이드 등)가 들여쓰기 관련 규칙을 어떻게 정의하는지 살펴봅니다. 또한 스페이스 대비 탭 사용의 장단점, 긴 라인을 어떻게 줄여나갈지에 대한 조언, 팀 내에서 일관성을 강제하는 방법 등을 다룰 것입니다.다양한 스타일 가이드의 예구글 C++ 스타일 가이드: 스페이스 사용 권장(2칸 들..
안녕하세요! 지난 글에서 성능 최적화 기초를 다루며 워크그룹 크기 조정, 메모리 접근 패턴 개선, 프로파일링의 중요성을 언급했습니다. 이번 글에서는 한 단계 더 나아가, OpenCL 프로그램을 디버깅하고 성능을 자세히 프로파일링하는 기본적인 방법을 살펴보려 합니다.디버깅과 프로파일링은 생각보다 중요한 영역입니다. 코드가 잘 동작한다고 생각했는데 결과가 이상하거나, 성능이 기대 이하일 수 있어요. 이때 단순히 코드를 쳐다보고 있는 것보다, 디버깅 툴이나 프로파일링 툴을 활용하는 것이 훨씬 효율적입니다.이번 글에서는 다음 내용을 다룹니다.디버깅 기초: 커널 실행 문제 파악, 에러 코드 확인프로파일링 툴 소개: 이벤트(event) 기반 타이밍, Nsight, Intel VTune 등호스트-디바이스 간 데이터 ..
지금까지 다룬 DQN 계열 알고리즘은 Q값(Q(s,a))을 근사하고, 이를 바탕으로 최적 행동을 선택하는 가치기반(Value-based) 방식이었습니다. 반면, 정책기반(Policy-based) 방법은 Q함수를 명시적으로 다루지 않고, 정책(π(a|s))을 직접 파라미터화(파라미터 θ)하고 이를 최적화하는 접근을 사용합니다.정책기반 접근의 장점:연속적이고 큰 행동 공간 처리 용이: Q테이블이나 Q함수를 모든 행동에 대해 근사하는 것이 어려운 상황에서 정책을 직접 근사하면 편리합니다.확률적 정책: 정책이 확률적으로 행동을 샘플링하기 때문에 탐색을 내장하고 있습니다.정책 개선의 직관성: 목표는 "정책의 기대 return을 최대화"하는 것이며, 이를 직접 최적화 가능합니다.이번 글에서는 가장 기초적인 정책기반..
지난 글에서는 러스트가 제공하는 동시성(Concurrency)과 병렬성(Parallelism) 지원을 살펴봤습니다. 이제 러스트가 제공하는 또 다른 강력한 기능들, 즉 매크로(Macro), 클로저(Closure), 그리고 함수형 패러다임을 지원하는 다양한 문법과 라이브러리, 마지막으로 프로젝트 빌드 과정에 개입할 수 있는 빌드 스크립트(Build Script) 개념을 살펴보며 러스트 생태계의 폭넓은 표현력을 확인해보겠습니다. C++에 익숙한 분이라면 템플릿 메타프로그래밍, 람다 함수, CMake나 Meson을 통한 빌드 설정을 생각해볼 수 있습니다. 러스트는 이와 유사한 기능을 가지면서도 안전성과 명확한 문법, 통합된 패키지 관리 체계로 개발자 경험을 향상시킵니다.매크로(Macro)C++에서는 전처리기 ..
이제 10개의 글에 걸친 “CUDA & Modern C++로 GPU 프로그래밍 시작하기” 시리즈를 마칠 시점입니다. 첫 글에서는 단순히 “Hello, GPU!”를 출력하는 예제부터 시작했지만, 이제는 Host-Device 메모리 관리, 스레드/블록/그리드 개념, 비동기 스트림, 메모리 계층(Shared/Constant), CMake 기반의 현대적 빌드, Modern C++ 기능 적용, 디버깅 및 프로파일링까지 다양한 주제를 맛보았습니다. 마지막으로 이 시리즈를 정리하며, 앞으로 여러분이 확장해나갈 수 있는 주제들을 안내하겠습니다.시리즈 정리환경 설정 & Hello GPU!: CUDA 개발환경(드라이버, 툴킷) 세팅 및 간단한 출력 예제를 통해 기본 틀을 잡았습니다.Host vs Device 코드 구조 이..
지금까지 이 시리즈를 통해 C++ 표준이 어떻게 발전해 왔는지, 그리고 그 과정에서 왜 오래된 구현이나 관용구를 버려야 하는지를 살펴보았습니다. auto_ptr부터 시작해, C-Style 배열, 매크로 상수, 전통적 for 루프, C-Style 문자열, printf, SFINAE 트릭, 구식 함수 객체와 std::bind, 직접 스레드 관리, 직접 구현한 알고리즘까지 — 이 모든 레거시 패턴들이 모던 C++에서는 훨씬 더 나은 대안으로 대체되고 있습니다.C++20 이후로 언어와 라이브러리는 더욱 풍부해졌습니다. std::unique_ptr로 명확한 메모리 소유권을 관리하고, std::array와 std::vector, std::span으로 컨테이너를 안전하게 다루며, constexpr와 enum clas..
과거 C++98/03 시절에는 표준 라이브러리가 제공하는 알고리즘도 제한적이었고, 특정 요구사항을 만족하기 위해 개발자가 직접 알고리즘을 구현하거나, 반복자 기반 STL 알고리즘을 복잡하게 조합해야 하는 경우가 많았습니다. 또한 병렬 처리나 고성능 연산을 위해서는 플랫폼별 스레드 관리나 OpenMP, TBB 같은 서드파티 라이브러리에 의존해야 했습니다.모던 C++20에서는 Ranges 라이브러리를 통해 알고리즘 파이프라인을 선언적으로 구성할 수 있으며, 병렬 알고리즘 지원을 통해 표준 라이브러리 레벨에서 병렬화를 쉽게 도입할 수 있습니다. 이렇게 하면 코드 가독성과 유지보수성이 대폭 개선되며, 성능 향상을 위한 병렬화도 간단히 적용할 수 있습니다.관련 참고 자료:C++20 RangesParallel al..
과거 C++98/03 시절, 멀티스레딩을 구현하기 위해서는 운영체제별 API(pthread, Win32 threads 등)를 직접 호출하거나, Boost Threads와 같은 서드파티 라이브러리에 의존해야 했습니다. 이는 코드 이식성을 저하시켰고, 스레드 생성, 종료, 동기화 관리가 번거롭게 이루어지는 경우가 많았습니다.C++11 이후 표준 라이브러리에 std::thread, std::mutex, std::lock_guard, std::async 등 기본적인 멀티스레딩 기능이 도입되었고, C++20에서는 std::jthread와 중단 요청(stop token) 메커니즘이 추가되어 스레드 관리가 더 단순해졌습니다. 또한 C++20 코루틴(coroutine)을 활용하면 비동기 처리를 더 간결하고 직관적으로 ..
과거 C++98/03 시절에는 함수 객체(function object) 클래스를 직접 정의하거나, std::bind를 통해 함수 호출을 커스터마이징하는 패턴이 흔했습니다. 하지만 이러한 방법은 코드가 장황해지고 의도를 분명히 드러내지 못하는 경우가 많았습니다. 호출 대상이 어디에 있는지, 어떤 인자를 바인딩했는지 일일이 추적해야 했으며, 이는 코드 가독성과 유지보수성에 악영향을 끼쳤습니다.모던 C++에서 이 문제를 해결하기 위해 람다(lambda) 표현식과 std::function을 사용할 수 있습니다. 람다는 익명 함수 객체를 간결한 문법으로 정의할 수 있고, 캡처를 통해 외부 변수를 자연스럽게 접근할 수 있습니다. 또한 std::function은 범용 함수 포인터 래퍼로, 다양한 호출 대상(람다, 함..