[C++] C++17 optional

언어/C++ 2018. 12. 30. 22:29

C++17부터 옵셔널 라이브러리가 추가되었다.


이 옵셔널 타입은 원래 함수형 언어에서 나온 개념인데, 개념적으로는 모나드라고 부른다.


예외처리 방법 중 하나며, 안전성이 높아서 명령형 언어들에서도 채용을 많이 하는 편이다.

C#의 Nullable이 그렇고, Swift의 옵셔널, 코틀린의 ??, 러스트의 Result 등이 있다.


단어 자체의 뜻을 보면 '선택적인'이라는 뜻인데. 값이 선택적으로 있을수도 없을수도 있다는 뜻이다.


좀 다르긴 하지만 포인터 타입도 이런 면에서 옵셔널의 특성을 가진다고 할 수도 있다. 

널 포인터를 가지면 값이 없는 것이고 뭐라도 갖고있으면 주소가 있는거니까 값이 있는 것이다.


옵셔널은 이러한 특성을 포인터뿐만 아니라 모든 타입에 적용시킬 수가 있다.

게다가 값이 들어있는지 아닌지 명시적으로 확인을 하게 해서 포인터에 비하면 아주 안전하다.

그대신 귀찮은 면이 있긴 하지만 어느정도 감수할만한 부분이라 생각된다.



옵셔널로 선언된 객체는 그 자체로는 사용할 수 없다.

값이 들어있는 상태인지 아닌지 모르기 때문이다.



옵셔널의 값을 사용하려면 value 메서드를 쓰면 된다. 

다만 값이 없을 때 쓰면 예외가 뜨니까 has_value나 operator bool로 값 여부를 체크하고 사용해야 한다.

"John"이라는 값이 멀쩡히 들어있으니 아주 잘 수행된다. 


값이 없으니 "??"가 나온다.


포인터에서 빈 주소를 표현하는 용도로 nullptr가 예약된것처럼

빈 옵셔널을 표현하는 객체로 nullopt가 있다.


근데 값을 사용할때마다 조건문을 달아주는건 꽤 귀찮은 작업이다.

위에서 했던건 value_or 메서드 하나로 퉁칠 수 있다.

이건 값이 들어있으면 값 그냥 반환하고, 값이 없으면 인자로 받은걸 반환한다.


'언어 > C++' 카테고리의 다른 글

[C++] R-Value Reference와 Move Semantic  (0) 2019.09.03
[C++] Q: 왜 동적배열이 vector가 된건가요?  (0) 2019.09.03
[C++] C++17 variant  (0) 2018.12.30

설정

트랙백

댓글

[C++] C++17 variant

언어/C++ 2018. 12. 30. 22:21

variant는 진화된 공용체다.


기존의 union은 문제가 많았다.


예를 들어 기존의 union을 쓸 때, 

double 버전으로 값을 넣고 int 버전으로 사용을 한다 해도 아무런 문제 없이 작동이 된다.


하지만 출력값을 보면 알겠지만 값이 정상적이지 않다.


C의 공용체는 아무런 타입 검사를 수행하지 않는다. 이 때문에 C의 공용체는 타입-safe하지 못하다고 한다.


아무튼 저런 맛이 간 출력값이 나온 이유는 아무런 조치 없이 메모리에 존재하는 비트값을 그대로 읽어왔기 때문이다. 정수 타입과 실수 타입의 메모리 구조는 완전히 다르다. 게다가 엔디언과 바이트 크기까지 고려하면 같은 계열의 타입이라도 괴리가 발생할 수가 있다.


물론 이런걸 이용해서 편법적으로 사용할 수도 있지만, 

실제로 이런 식의 접근은, 99% 사용자의 실수에서 발생한다. 그리고 실수는 결함으로 이어진다.

union은 이처럼 안전성에 문제가 많다.


게다가 기존의 union은 생성자/소멸자/가상메서드가 없는 이른바 POD 타입만을 멤버로 둘 수가 있다는 심각한 기능적 결함이 있었다.

다시말해 C++스타일의 타입은 제대로 담아둘수 없었다는 것이다.



C++17에서는 이런 문제들을 해결한 variant라는 멋진 녀석을 내놓았다.


variant는 타입-safe한 공용체 템플릿이다.

당연히 C++ 스타일의 클래스도 멤버로 둘 수 있다.


기존의 공용체와 다른 특징으로, 이녀석은 반드시 초기화를 해야만 접근 타입을 바꿀 수가 있다.

해당 타입으로의 초기화를 수행하지 않고 접근을 한다면 예외가 발생한다.

아마 이런 방식을 통해서 타입체킹도 엄격하게 하고 생성자/소멸자도 써먹을 수 있게 한 것 같다.



일단 아래 코드는 아주 정상적으로 작동하는 코드다.

int 타입으로 값 대입 한번 해주고, 접근해서 출력하고.

double로 초기화해주고, 접근해서 출력한다.




하지만 초기화를 수행하지 않으면 이렇게 예외가 나온다.

이렇게



그리고 애초에 없는 타입이나 인덱스는 당연히 컴파일부터가 안 된다.



암튼 그렇다.


자세한 건 레퍼런스를 참조

https://en.cppreference.com/w/cpp/utility/variant

'언어 > C++' 카테고리의 다른 글

[C++] R-Value Reference와 Move Semantic  (0) 2019.09.03
[C++] Q: 왜 동적배열이 vector가 된건가요?  (0) 2019.09.03
[C++] C++17 optional  (0) 2018.12.30

설정

트랙백

댓글