들어가기
이번에는 C++11에서 nullptr, using, enum class에 대해서 살펴보자.
작성자: ospace114@empal.com, http://ospace.tistory.com/
nullptr 사용
기존 NULL 또는 0 대신에 사용할 수 있는 nullptr가 있다. NULL도 내부적으로 0으로 정의되어 있는 경우가 대부분이다. 이는 0값과 혼동이 발생할 수 있기 때문에 nullptr을 사용을 권장하다. 이는 템플릿 사용할 때에 형식 연역시 유용하다. 기존 NULL은 int 형식으로 인지하면서 에러가 발생할 수 있다.
template<typename FuncT, typename PtrT>
auto foo(FuncT& func, PtrT ptr) {
return func(ptr);
}
int f(std::shared_ptr<Box> spb);
foo(f, NULL); // 에러
foo(f, nullptr);
nullptr인 객체는 조건 식에서는 false으로 처리된다.
int *val = nullptr;
if (val) {
std::cout << *val << std::endl;
} else {
std::cout << "val is null." << std::endl;
}
using 사용
typedef에 의해서 타입을 정의해서 사용했다. 템플릿 클래스의 긴 표현식을 별칭으로 짧게 줄여쓰는데 유용했다. 이를 using이라는 별칭선언(alias declaration)으로 대처할 수 있고 활용도도 더 좋다.
typedef std::unique_ptr<std::vector<std::string>> PtrStrings;
using PtrStrings = std::unique_ptr<std::vector<std::string>>;
typedef void (*FP)(void);
using FP = void (*)(void);
그리고 using에서 템플릿을 사용해서 별칭 선언도 할 수 있다. 이를 이용해 C++14에서 remove_const_t가 아래처럼 선언되어 있다.
template<typename T>
using remove_const_t<T> = typename remove_const<T>::type
enum 사용
C++98가지는 범위없는(unscoped) enum으로 열거자들이 범위 없이 그대로 사용된다. 열거자들은 암묵적으로 0에서 0xFFFFFFFF까지 값을 할당할 수 있다. 작은 값은 char형 큰 값은 int형으로 선택된다. 초기값이 미정될 경우 0부터 차례로 값이 할당된다.
#include <iostream>
enum Color { red, green, blue };
int main() {
std::cout << " green is " << green << ".\n";
}
C++11부터는 enum class 구문으로 범위있는(scoped) enum을 사용한다. enum class 사용으로 같은 이름을 사용할 위험이 적다. 그리고 정수형 데이터가 아니기에 잘못된 값 비교로 인한 잠재적 위험을 줄인다. 물론 static_cast을 이용해서 이전처럼 정수형, 혹은 다른 형으로 변환해서 사용할 수 있다.
#include <iostream>
enum class Color { red, green, blue };
int main() {
Color green = Color::green;
int greenVal = static_cast<int>(green);
std::cout << " green is " << greenVal << ".\n";
}
enum이 기본 형식이 char 혹은 int로 고정되어 있지만 enum class는 기본 int을 사용하거나 변경할 수도 있다.
enum class Color; // 기본 형식 int
enum class Color : std::uint32_t; // 기본 형식 uint32_t
enum class을 사용할 때 장점으로 전방선언을 할 수 있다. 기존 enum은 사용할 경우 반드시 include해서 사용해야 한다. 그래서 보통 헤더에 포함되는데 enum이 수정될 때마다 관련 모든 파일을 재 컴파일해야 한다. 정방선언을 사용할 경우 헤더는 변경되지 않고 별도 소스에서 enum class을 정의하기 때문에 재 컴파일해야하는 경우를 줄일 수 있다.
enum class Color;
void displayColor(Color c);
기존 enum과 tuple을 활용팁이다.
// enum과 tuple에 필드를 순서를 유지하여 서로 연관시킴
enum UserFields { uiName, uiEmail, uiReputation };
using UserInfo = std::tuple<std::string, std::string, std::size_t>;
UserInfo user;
auto email = std::get<uiEmail>(user);
enum class을 사용할 경우 코드가 장황해진다. 물론 범위로 인한 이름 오염은 줄어든다.
// enum class를 바탕형식으로 변환되고 std::get을 위해 noexcept로 정의
template<typename E>
constexpr auto toUType(E enumerator) noexcept {
return static_cast<typename std::underlying_type<E>::type>(enumerator);
}
enum class UserFileds { uiName, uiEmail, uiReputation };
using UserInfo = std::tuple<std::string, std::string, std::size_t>;
UserInfo user;
auto email = std::get<toUType(UserFields::uiEmail)>(user);
C++14는 std::unerlying_type_t로 좀던 간편하게 사용할 수 있다.
마무리
이전에도 NULL이 없을 때 0을 NULL로 정의해서 사용했었다. nullptr을 사용하면서 좀더 명확히 처리할 수 있게 되었네요. 또한 using으로 더 쉽고 간단하게 타입을 정의해서 사용할 수 있습니다.
최대한 쉽고 간략하게 정리했는데, 여러분에 도움이 되었으면 합니다. 즐프하세요. ospace.
참고
[1] 스콧 마이어스 저, 류광 역, Effective Modern C++, 인사이트
'3.구현 > C or C++' 카테고리의 다른 글
[c++] 특수 멤버함수 사용하기: 복사 생성자/배정 연산자, 이동 생성자/배정 연산자, =default, =delete (1) | 2023.11.30 |
---|---|
[c++] override, const_iterator, noexcept, constexpr 사용하기 (0) | 2023.11.28 |
[c++] decltype, auto, 중괄호 초기화 사용하기 (0) | 2023.11.25 |
[c++] C++14 형식연역 (1) | 2023.11.21 |
[c++] C++11 보편참조 사용하기 (0) | 2023.11.20 |