전체 글 135

Effective Modern C++ #38 스레드 핸들 소멸자들의 다양한 행동 방식을 주의하라

38. 스레드 핸들 소멸자들의 다양한 행동 방식을 주의하라joinable std::thread 를 파괴하면 프로그램이 종료된다.하지만 미래 객체의 소멸자는 언제는 암묵적 join, 언제는 암묵적 detach 의 동작을 한다.이러한 스레드 핸들 소멸자의 동작 확인을 위해, 확인해야하는 상태가 있다. 위 그림처럼 미래 객체는 호출자에서, 피호출자 결과를 받을 수 있는 채널이다. ( 통신 채널의 한쪽 끝 )그렇다면 피호출자 결과는 어디에 저장될까?후보 1) 피호출자호출자가 미래 객체.get 호출하기 전에 피호출자가 종료될수 있음따라서 피호출자에 저장 불가능후보 2) 호출자 미래 객체std::future 로 std::shared_future 를 생성하면 미래객체 결과의 소유권이 이전됨원본 호출자의 미래 객체가 ..

dev/C++ 2025.07.05

Effective Modern C++ #37 std::thread 들을 모든 경로에서 unjoinable (합류 불가능)하게 만들어라

37. std::thread 들을 모든 경로에서 unjoinable (합류 불가능)하게 만들어라std::thread 객체는 joinable 또는 unjoinable 상태이다.unjoinable std::thread 객체는 다음과 같다.기본 생성 std::thread이동된 후 남겨진 std::threadjoin 에 의해 합류된 std::threaddetach 에 의해 탈착된 std::thread합류 가능 (joinable) 한 스레드의 소멸자가 불리는 경우, 프로그램이 종료 (terminate)된다.프로그램이 종료되는 이유는, 그 이외의 동작보다는 더 나은 선택이기 때문이다.암묵적 joinstd::thread 소멸자가 background 비동기 thread를 기다리는 것추적하기 어려운 성능 이상이 나타날 ..

dev/C++ 2025.07.03

Effective Modern C++ #36 비동기성이 필수일 때에는 std::launch::async 를 지정하라

36. 비동기성이 필수일 때에는 std::launch::async 를 지정하라일반적으로 std::async 를 호출해서 함수를 실행하는 것은 비동기적으로 실행하겠다는 의도가 존재한다.하지만 항상 그러한 의미로 사용되지 않는다.std::async 호출은 함수를 어떤 launch policy (시동 방침) 에 따라 실행한다는 더 일반적인 의미를 가진다. 함수 f 를 std::async 통해 실행할 때, 다음 launch policy을 인자로 사용할 수 있다.std::launch::asyncf 는 비동기적으로 (다른 스레드에서) 실행됨std::launch::deferredstd::async 가 리턴한 std::future 객체로 get/wait 호출되어야만 f 실행 가능f 의 실행은 그러한 호출까지 지연됨(d..

dev/C++ 2025.07.02

Effective Modern C++ #35 스레드 기반 프로그래밍보다 과제 기반 프로그래밍을 선호하라

동시성 APIC++11 의 큰 성과는 동시성을 언어와 표준 라이브러리에 도입한 것이다.다른 스레드 기능에 비해 제약도 큰데, C++의 동시성 지원의 상당 부분이 컴파일러 작성자에 대한 제약의 형태이기 때문이다.표준 라이브러리에서 future 객체를 위한 템플릿은 2개이며, 해당 장에서는 둘의 구분이 중요하지 않은 경우 미래 객체라고 통칭한다.( std::future, std::shared_future )35. 스레드 기반 프로그래밍보다 과제 기반 프로그래밍을 선호하라비동기적 실행의 방법은 크게 두가지가 있다.thread-based 프로그래밍std::thread 객체 생성해서 그 객체에서 함수 실행한다.예시)int doAsyncWork();std::thread t(doAsyncWork); task-base..

dev/C++ 2025.07.02

Effective Modern C++ #34 std::bind 보다 람다를 선호하라

34. std::bind 보다 람다를 선호하라std::bind 는 C++98 의 std::bind1st, std::bind2nd 를 계승했으며 2005년 표준 라이브러리의 일부이기도 했다.하지만 C++14 이상부터는 람다가 std::bind 보다 우월한 선택이므로 람다를 사용하자.*C++11 에서는 특정 케이스에서만 std::bind 사용이 용인된다. std::bind 와 비교했을 때, 람다의 장점은 다음과 같다.1. 가독성람다 예시)void setAlarm(Time t, Sound s, Duration d);// 한시간 후부터 지정된 소리를 30초간 재생auto setSoundL = [](Sound s) { using namespace std::chrono; using namespace std::lit..

dev/C++ 2025.06.30

Effective Modern C++ #33 std::forward 를 통해서 전달할 auto&& 매개변수에는 decltype 을 사용하라

33. std::forward 를 통해서 전달할 auto&& 매개변수에는 decltype 을 사용하라C++14 에서 가장 exciting 한 기능은 매개변수에 auto를 사용할 수 있는 general lambda 기능이다.람다 클로저 클래스의 operator 를 템플릿 함수로 만들어서 임의로 구현할 수 있다.예시)auto f = [](auto x){ return normalize(x); };// 위 람다함수 auto 구현하는 법class 컴파일러가_만든_이름 { public: template auto operator()(T x) const { return normalize(x); } ...};이제 위 케이스에서 x 가 l-value 또는 r-value 인자로 전달된다고 가..

dev/C++ 2025.06.30

Effective Modern C++ #32 객체를 클로저 안으로 이동하려면 초기화 캡쳐 (갈무리)를 사용하라

32. 객체를 클로저 안으로 이동하려면 초기화 캡쳐 (갈무리)를 사용하라값 캡쳐, 참조 캡쳐 모두 사용하기 애매한 경우가 있다.이동 전용 객체 (ex. std::unique_ptr )를 클로저 안으로 들여올 때가 그렇다.C++11 에서는 방법이 없지만. C++14 에서는 객체를 클로저 안에 이동하는 기능을 제공한다.Init Capture (초기화 캡쳐) 방식이 있는데 기본 캡쳐 모드 외에는 C++11 캡쳐 모드에서 지원하는 기능 전부 지원한다.초기화 캡쳐는 다음과 같은 항목 지정이 가능하다.람다로부터 생성되는 클로저 클래스의 자료 멤버 이름해당 자료 멤버 초기화 표현식예시)auto pw = std::make_unique();...auto func = [pw = std::move(pw)] { return ..

dev/C++ 2025.06.30

Effective Modern C++ #31 기본 Capture mode를 피해라

람다 표현식C++의 면모를 크게 바꾸는 새로운 기능이다.사실 람다가 할 수 있는 모든 일은 람다를 사용하지 않고도 구현할 수 있다.하지만 함수 객체 만들기가 쉬워지므로 C++ 개발에 큰 영향을 준다. 람다 표현식이 없다면 std::find_if, std::remove_if, std::count_if 등은 조건자(predicate)와 사용만 가능하다.*ex. std::find_if(v.begin(), v.end(), isEven); 에서 3번째 인자에 들어가는 것이 predicate (함수 포인터, 함수 객체 등)커스텀 가능한 비교 연산(std::sort, std::nth_element, std::lower_bound 등)도 마찬가지이다. 람다 표현식의 예시)std::find_if(container.beg..

dev/C++ 2025.06.30

Effective Modern C++ #30 완벽 전달이 실패하는 경우들을 잘 알아두라

30. 완벽 전달이 실패하는 경우들을 잘 알아두라Perfect Forwarding 은 C++11 의 주요 기능 중 하나이다.한 함수가 다른 함수에 자신의 인자를 전달할 때, 다른 함수에 받은 것과 동일한 객체를 전달하는 방법이다.( ex. 값 매개변수를 사용하는 경우 복사본을 전달하므로 동일한 객체가 아니다 ) 객체 전달 외에도 l-value/ r-value 여부, const, volatile 여부 등 전달되는 객체의 특징도 포함한다.따라서 보편 참조 매개변수를 사용해야한다.(#23에서 다룬 내용) 보편 참조 매개변수만 l-value, r-value 정보를 저장하기 때문이다.예시)templatevoid fwd(T&& param) { f(std::forward(param));}위와 같이 완벽 전달은 특정 ..

dev/C++ 2025.06.30

Effective Modern C++ #29 이동 연산이 존재하지 않고, 저렴하지 않고, 적용되지 않는다고 가정하라.

29. 이동 연산이 존재하지 않고, 저렴하지 않고, 적용되지 않는다고 가정하라.move semantics (이동 의미론)는 C++11 의 가장 주요한 기능이다.컴파일러는 비싼 복사 연산을 비교적 저렴한 이동 연산으로 대체할 수 있다. (가능하면 그렇게 해야한다)또한 C++98 코드 기반을 C++11 준수하는 컴파일러와 표준 라이브러리로 컴파일하면, 소프트웨어가 자동으로 더 빠르게 실행된다. (컨테이너 등 내부적 로직에서 이동 연산이 사용되므로 자동 개선) 개발자들은 이동 연산에 열광하나, 과장된 부분도 분명 존재한다.이번 시간에는 이동 의미론에 대해 근거 있는 기대를 가질 수 있게 자세히 알아보자. move semantics 를 지원하지 않는 형식도 다수 존재한다.특수 멤버 함수 자동 생성 조건에 맞지 ..

dev/C++ 2025.06.28