Std::Variant는 C++ 17에서 지원하는 공용체이다.
공용체란 한 인스턴스에 다양한 타입의 값을 담을 수 있는 구조체를 의미한다. 공용체라면 가장 쉽게 접할 수 있는게 명시적인 Union 일텐데, 현재 Std::Variant는 Value와 함께 저장된 값의 유형을 식별하는 판별자를 관리하기 때문에 공용체를 구현하는데 보다 안정적인 방법으로 선호되고 있다.
(기존의 Union의 경우 타입을 판별하지 않기때문에 논리 오류로 이어질 수 있다는 단점이 존재한다.)
* Variant의 이용방법은 다음과 같다.
https://en.cppreference.com/w/cpp/utility/variant
* 구조체의 사이즈는
Union과 동일하다. 공용체에 속한 Struct중에서 가장 큰 사이즈의 타입을 기준으로 8바이트를 더해 모든 인스턴스들이 동일한 크기를 가진다. 이러한 사항을 메모리풀을 통한 객체할당 방식을 이용할 때 유의할 것.
struct A{
int a;
};
struct B{
long long b;
long long c;
};
A a;
B b;
cout << "size of a:" << sizeof(a) << endl;
cout << "size of b:" << sizeof(b) << endl;
variant<struct A, struct B> v, w;
v = a; // v contains int
cout << "size of variant v:" << sizeof(v) << endl;
* 항상 초기화가 필요하다.
최근 오랜만에 포스팅을 결심하게 된 이유이다. 앞서 말했듯이 Variant는 기존 Union과 달리 값의 유형을 식별하는 판별자를 관리한다. 이러한 판별자(Access Type)는 초기화와 동시에 액세스 타입을 설정하게 되는데, 이러한 초기화 과정을 거치지 않거나, 설정된 판별자와 다른 타입의 값을 사용할 경우, 해당 Variant에서 명시하는 bad_Variant_Access를 마주하게 된다. 해당 Vairant의 판별자가 논리오류를 방지하는 안전장치 역할을 수행하는데, 필자와 같이 모던 C++에 능숙하지 않은 사용자에게는 한 차례 걸림돌이 된다 할 수 있다.
해당 형식에서 어긋난 get<int>부분에서 bad_variant_access가 발생함을 확인할 수 있다. 이는 variant를 초기화 하지 않고 사용하는 과정에서도 발생할 수 있다. (값을 들고 있지 않은 경우는 std::monostate를 활용하면 표현이 가능하지만 아직 필요성을 느끼진 못했다)
필자의 경우 union 의 공용체들이 공통적으로 wchar_t* 변수를 가져 초기화 없이 copy_n을 사용하다 오류를 경험했다.문자열 구조체의 경우에도 variant에 값을 대입하기 이전에는 '{}' 빈 초기화 리스트를 이용해서라도 초기화를 거쳐야 한다.
'Language > C++' 카테고리의 다른 글
상수 멤버함수의 설계 방법 (0) | 2022.03.02 |
---|---|
참조 전달 문법 std::move, std::forward (0) | 2022.01.13 |
이동생성자와 보편참조법(universal ref) (0) | 2022.01.07 |
enable_shared_from_this의 사용법 (0) | 2022.01.04 |
lvalue와 rvalue + 우측값 참조법 (0) | 2021.12.21 |