Computer Science/CPP, C#

CPP26 공식 채택

카세우스 2026. 3. 31. 20:41

CPP 23 강의할때 언젠간 되리라고 언급만 했는데.. 진짜 되네...

ISO 위원회가 CPP26을 발표했습니다. 물론 위대한 클로드님과 제미나이님께서 개발자들을 대체하는 상황에서 의미가 있겠나 싶지만.... 쨋든 혁신적이라면 아주 혁신적인 내용이 대거 포함되어 있습니다.

 

Reflection

대충 언어가 자기 자신을 기술하고, 그 정보를 바탕으로 코드를 생성할 수 있게 되었습니다. 그니까 정확히 무슨소리냐면, Serialization같은걸 예전에는 매크로나 Qt MOC등에 던져서 했다면 이제는 언어 자체가 이걸 수행한다는 얘기입니다. 쉽게 말하면 프로그램이 자기의 구조(type, field, function 등)을 Introspection(자기 관찰)할 수 있게 되었다는 겁니다.

 

사실 예전에는 Reflection이라고 해봤자 RTTI(Run TIme Type Information, 대충 런타임 중에 포인터가 가리키는 놈이 뭔지 알게 해주는 것)정도가 있었습니다. 그렇지만 이번 CPP26 리플렉션은 컴파일타임에 구조체의 모든 필드를 열거하고, 각각에 대해서 코드를 생성할 수 있는 정도입니다!

 

// std::meta::info == 모든 Reflection 결과의 기본 타입
// auto meta = ^MyStruct;와 같이 Reflection Operator(^)가 생김
// meta::get_name(...)와 같이 컴파일 타임에 실행되는 reflection 결과를 조작하는 함수들 생김
//[: refl :] 처럼 reflection결과를 다시 코드로 삽입하는 Splicing이 됨

//Example 1
for (meta::member m : meta::members(^T)) {
    // 이름, 타입 다 접근 가능
}

//Example 2
struct User {
    int id;
    std::string name;
};

to_json(user); // -> 이렇게 하면 필드 자동 탐색해서 JSON이 생성되는 기적 발생

 

아 물론 JAVA처럼 Runtime에서 돌리는건 아니고 Compile Time에서 돌립니다.

 

 

메모리 안전성

- 초기화 되지 않은 지역변수 읽기가 더이상 UB(Undefined Behavior)가 아닙니다. CPP 26에서는 이를 erroneous behavior로 정의합니다. UB는 개발자들에게 끔찍한 악몽을 선사하긴 합니다만, EB는 최소한 예측은 된다는 장점이 생겼습니다. 아 물론 런타임 비용이 들기 때문에, 끌 수도 있습니다.

- Hardened Standard Library(잘못된 사용을 했을때, 적극적으로 막거나 감지하는 라이브러리)에 대해서 범위 검사를 기본적으로 제공하게 되었습니다. 덕분에 많은 대기업에서 버그를 열심히 때려잡고 있습니다. Rust의 철학이 살짝 스며든 느낌이네요.

 

Contracts

Function/Code가 반드시 만족해야 하는 조건을 언어 차원에서 명시하고, 위반 시 정의된 방식으로 처리하는 시스템. Precondition/Postcondition/contract_assert 등으로 구성됨.

- assert를 잠시 생각해봅시다. 이친구는 사실 딱히 디버그 할때만 쓰지 컴파일러는 나몰라라 합니다. 그러나 Contracts는 컴파일러가 인지하고, 때려 잡을지 안 때려 잡을지를 결정하는 강제되는 규칙입니다.

- 그러니까, UB로 터지는 대신에 정확한 위치에서 fail-fast 지지겠다는 겁니디.

- 다만 계약을 위반했을 때 프로그램을 폭파할지, 예외를 던질지, 무시할지, UB로 취급할지를 표준이 정해야 하는데.. 이게 머리 아픈건 둘째 치고 이걸 체크하는거 자체가 Cost가 나가기에 말이 좀 많은 기능입니다.

 

std::execution

- 동시성과 병렬성을 표현하고 제어하는 통합 프레임 워크입니다. 그러니까 뭔소리냐면... "비동기 작업을 값처럼 다루고, 안전하게 연결해서 실행하는 표준 프레임워크"라고 할 수 있겠습니다. (Python의 Asyncio 생각하면 편합니다.)

- 과거 CPP에서는 비동기 코드 쓰면 std::future/promise/async/thread를 동원해서 지지고 볶아야 하는데.. 실행 흐름이 흩어지고 생명 주기 관리에 눈물이 났습니다. std::execution은 이를 Sender(미래에 값을 생산할 작업)/Receiver(결과/에러/취소를 받는 쪽)로 나누고 실행 단위를 Sender+Receiver로 합친 Operation State로 구현했습니다.
- 여튼 개념이 복잡한데, 자세히 설명하려면 저도 눈물이 나는 관계로... 따로 공부하시는 것을 추천드립니다.