string_view는 c++ 17에서 추가되었습니다.
string_view는 다양한 문자열 타입을 전달 받을 수 있는 안전하면서 효과적인 방법을 제공합니다.
내부적으로 문자열에 대한 pointer와 길이만 가지므로 임시객체를 생성하지 않고 문자열을
사용 할 수 있습니다.
주의 할점은 string_view는 내부적으로 null 종료 문자를 가지지 않습니다.
(사실 string 타입류는 size를 들고 있기 때문에 null문자가 없어도 됩니다. )
또한 원본 데이터에 대한 변경을 방지합니다.
string_view를 사용시에 주의 할 점은 원본 데이터에 대한 객체의 수명을 제어 할 수 없기 때문에
호출 하는 주체가 원본 데이터의 안정성을 보장 해 줘야 합니다.
string_view는 암시적 변환이 지원되면 template을 사용하지 않고도 다양한 타입의 문자열을 전달 받아 사용할 수
있습니다.
string_view 기본 타입
string_view 타입들을 내부적으로 std::basic_string_view<T>로 구현되어 있습니다.
이 름 | 설 명 |
string_view | std::basic_string_view<char> |
wstring_view | std::basic_string_view<wchar_t> |
u16string_view | std::basic_string_view<char16_t> |
u32string_view | std::basic_string_view<char32_t> |
string_view를 사용하기 위한 Visual Studio 2019 셋팅
vs2019의 경우 기본값이 c++14로 설정되어 있습니다. string_view를 사용하기 위해서는
c++17이 지원되도록 환경 설정을 변경해야합니다.
솔루션 탐색기 -> 프로젝트 우클릭 -> 구성 속성 -> 일반 -> C++ 언어 표준 변경을 C++ 17로 변경합니다.
sring_view 사용하기
sring_view는 2가지 방법으로 사용 할 수 있습니다.
- 문자열 전체 전달
- 문자열의 부분 전달
int main() {
// 전체 문자열 전달
std::string_view sv1("123456789");
copy(sv1.begin(), sv1.end(), ostream_iterator<char>(cout)); // 123456789 출력
cout << '\n';
cout << sv1.data() << '\n'; // 123456789 출력
// 부분 문자열 전달
std::string_view sv2("123456789", 2);
copy(sv2.begin(), sv2.end(), ostream_iterator<char>(cout)); // 12 출력
cout << '\n';
// data함수를 사용하면 const char *를 리턴하기 때문에 '\0' 까지 출력
// 부분 문자열을 사용하려면 begin(), end()형태로 사용 필요
cout << sv2.data() << '\n'; // 123456789 출력
sring_view 장점
// c++ 14버전
std::string FiveCharacterOnlyString(const std::string & str)
{
if (str.size() < 5) return str;
return str.substr(0, 5);
}
// c++ 17 string_view
// string_view를 사용하면 string 객체의 복사가 발생하지 않습니다.
std::string_view FiveCharacterOnlyStringView(const std::string_view str)
{
if (str.size() < 5) return str;
return str.substr(0, 5);
}
// std::string val1 = "12345"
auto val1 = FiveCharacterOnlyString("123456789");
// std::string_view val2 = "12345"
auto val2 = FiveCharacterOnlyStringView("123456789");
예제를 보시면 std::string으로 구현 된 FiveCharacterOnlyString를
std::string_view로 구현 된 FiveCharacterOnlyStringView 함수로 대체 할 수 있습니다.
FiveCharacterOnlyString를 사용하게 되면 std::string타입의 복사본이 생성되게 됩니다.
FiveCharacterOnlyStringView를 사용하게 되면 복사본 생성 없이 효율적으로 동작할 수 있도록 지원합니다.
void UsedString(std::string & str)
{
// string 원본 객체에 대한 변경이 이루어 집니다.
str = "실수로 데이터 변경 시도";
}
void UsedStringView(std::string_view str_v)
{
// string_view 원본 객체에 대한 변경이 발생하지 않습니다.
str_v = "실수로 데이터 변경 시도";
}
추가적으로 std::string_view를 사용하게 되면 실수로 데이터를 변경을 해도 전달 받은 원본 객체에 대해서
안전하게 사용 할 수 있습니다.
또한 std::string이 지원하는 다양한 멤버함수를 std::string_view도 지원하기 때문에 손쉽게 사용 할 수 있습 니다.
void CallerOriginStringObject(std::string_view str_v, std::string& str)
{
std::cout << "[origindata] str_v = " << str_v.data() << " Size = " << str_v.size() << std::endl;
str = "modify";
// 원본데이터가 변경되면 string_view의 데이터가 변경됩니다.
// 문자열 : "modify", size = 15
// 남아있는 빈 공간에는 이전 데이터가 들어 있습니다.
std::cout << "[origindata modify] str_v = " << str_v.data() << " Size = " << str_v.size() << std::endl;
}
int _tmain(int argc, _TCHAR* argv[])
{
std::string str("original string");
CallerOriginStringObject(str, str);
}
위에서도 설명했듯이 string_view 자체는 원본 데이터를 수정 할 수 없지만
바라보고 있는 원본 데이터가 수정되면 string_view 문자열 데이터도 수정됩니다.
주의할 점은 size 정보는 처음 원본데이터를 할당 받을 당시의 size로 고정되어 있기 때문에 예상하지 않은 동작이
발생 할 수 있습니다.
그렇기 때문에 string_view를 사용 도중에는 호출하는 입장에서 원본 데이터가 수정되지 않을 것을 보장해줘야 합니다.
내부 동작 방식
std::string_view가 구현된 소스 코드를 확인 해 보면 basic_string_view 이라는 템플릿 클래스로 구현된 것을 확인
할 수있습니다.
객체의 사이즈
template <class _Elem, class _Traits>
class basic_string_view { // wrapper for any kind of contiguous character buffer
//... 생략
private:
//... 생략
const_pointer _Mydata;
size_type _Mysize;
}
basic_string_view는 내부적으로 문자열 포인터와 사이즈를 저장하는 변수만을 가집니다.
문자나 std::string 타입보다 가볍게 동작 할 수 있습니다.
const_point 형태로 보유하기 때문에 원본 데이터를 수정 할 수 없고 읽기 전용으로만 사용 가능 합니다.
변 수 | 타 입 | 설 명 |
_Mydata | const_point | 템플릿 인자로 입력받은 문자열 포인터의 const형 포인터를 가집니다. _Mydata는 전달 받은 문자형 데이터의 배열 [0]의 위치를 가집니다. |
_Mysize | size_type = size_t | 전달 받은 문자형 데이터의 사이즈를 저장합니다. |
객체 생성 및 할당 방식
template <class _Elem, class _Traits>
class basic_string_view { // wrapper for any kind of contiguous character buffer
//... 생략
constexpr basic_string_view() noexcept : _Mydata(), _Mysize(0) {}
constexpr basic_string_view(const basic_string_view&) noexcept = default;
constexpr basic_string_view& operator=(const basic_string_view&) noexcept = default;
constexpr basic_string_view(_In_z_ const const_pointer _Ntcts) noexcept
: _Mydata(_Ntcts), _Mysize(_Traits::length(_Ntcts)) {}
constexpr basic_string_view(_In_reads_(_Count) const const_pointer _Cts, const size_type _Count) noexcept // strengthened
: _Mydata(_Cts), _Mysize(_Count) {
#if _CONTAINER_DEBUG_LEVEL > 0
_STL_VERIFY(_Count == 0 || _Cts, "non-zero size null string_view");
#endif // _CONTAINER_DEBUG_LEVEL > 0
}
private:
//... 생략
}
string_view의 생성자 동작 방식을 확인 해 보면 매우 간단한데 전달 받은 문자열 데이터의 포인터 및 사이즈를
저장합니다.
그림과 같이 문자열에 대한 데이터를 설정합니다. 설정 비용은 pointer하나와 size_t 변수 값에 대한 변경 만으로
가능 합니다.
string_view에 새로운 문자열을 배정하면 그림과 같이 새로운 문자열을 바라보도록 데이터를 셋팅합니다.
string_view 관련 참조 사이트
https://docs.microsoft.com/en-us/cpp/standard-library/string-view?view=vs-2019
https://en.cppreference.com/w/cpp/string/basic_string_view
'c++ > modern c++' 카테고리의 다른 글
[c++] std::lock 관련 함수들 (0) | 2020.05.22 |
---|---|
[c++] std::mutex (0) | 2020.03.28 |
[c++] constexpr 키워드 (0) | 2020.03.19 |
[c++] auto와 decltype 키워드 (0) | 2020.03.15 |
[c++] std::move와 std::forward (4) | 2020.03.07 |