1. 개요
오늘은 C++17에 variant에 대해 알아보겠습니다.
2. variant
variant는 C++17에 나온 공용체입니다.
기존의 union은 문제가 있습니다.
예를들어 기존의 union을 쓸 때, double버전으로 값을 넣고 int버전으로 사용을 한다 해도 아무런 문제 없이 작동이 되었습니다.
#include<iostream>
using namespace std;
union Union
{
int nValue;
double dValue;
};
아무런 이상없이 컴파일이 된다.
하지만 출력값이 쓰레기값이들어간건지 이상합니다.
C의 공용체는 아무런 타입 검사를 수행하지 않습니다.
이 때문에 C의 공용체는 타입 -safe하지 못한다고 합니다.
저런 출력값이 나온 이유는 아무런 조치 없이 메모리에 존재하는 비트 값을 그대로 읽어왔기 때문입니다.
정수 타입과 실수 타입의 메모리 구조는 완전히 다르며 또한, 엔디언과 바이트 크기까지 고려하면 같은 계열의 타입이라도 괴리가 발생할수가 있습니다.
이러한 해결점을 위해 C++17에 variant를 내놓았습니다.
C++ 스타일의 클래스도 맴버로 둘 수 있으며 반드시 초기화를 해야지만 접근 타입을 바꿀수가 있고 초기화를 수행하지 않는다면 예외가 발생합니다.
타입 체킹도 엄격하며 생성자 소멸자도 사용이 가능합니다.
#include<iostream>
#include<variant>
using namespace std;
int main()
{
variant<int, double> va;
get<int>(va) = 100;
cout << get<0>(va) << '\n';
va.emplace<double>(3.14);
cout << get<1>(va) << '\n';
return 0;
}
하지만 만약 초기화를 안한다면 아래처럼 나옵니다.
#include<iostream>
#include<variant>
using namespace std;
int main()
{
variant<int, double> va;
get<int>(va) = 100;
cout << get<0>(va) << '\n';
get<double> (va)= 3.14;
cout << get<1>(va) << '\n';
return 0;
}
그리고 애초에 없는 타입이나 인덱스는 컴파일이 안됩니다.
#include<iostream>
#include<variant>
using namespace std;
int main()
{
variant<int, double> va;
get<string>(va) = 100;
cout << get<0>(va) << '\n';
get<double> (va)= 3.14;
cout << get<1>(va) << '\n';
return 0;
}
위에 보시면 int 는 get으로 대입이 가능했지만 double은 안됬습니다.
그것은 variant 자체가 디폴트 접근이 0 인덱스이므로 바로 int로만 접근이 가능하기 때문입니다.
따라서 이렇게 초기화를 진행시키는것도 좋은 방법인거 같습니다.
#include<iostream>
#include<variant>
using namespace std;
int main()
{
variant<int, double> va;
va.emplace<int>(100);
cout << get<0>(va) << '\n';
va.emplace<double>(3.14);
cout << get<1>(va) << '\n';
return 0;
}
그리고 디버깅을 거치면서 안 내용은 emplace를 하면 인덱스번호가 바껴 메모리상에 double만 올려지는거 같습니다.
아마 공용체가 double 8바이트로 채워져서 사용하기 떄문인거같습니다.
'개발자 면접 공부 > C-C++' 카테고리의 다른 글
스마트 포인터의 new와 make의 차이 (1) | 2023.10.03 |
---|---|
Inline 에 대하여 (2) | 2023.09.25 |
C++ 17 구조적 바인딩 (2) | 2023.09.14 |
C++ 11 tuple (0) | 2023.09.13 |
함수에 const 위치에 따른 결과 (0) | 2023.09.09 |