1. std::string_view
C++17 이전에는 읽기 전용 스트링을 받는 함수의 매개변수 타입을 쉽게 결정할 수 없었다.
const char*로 지정하면 std::string을 사용하는 클라이언트에서 c_str()나 data()를 이용하여 string을 const char*로 변환해서 호출해야 한다.
C++17부터 추가된 std::string_view 클래스를 사용하면 이러한 고민을 해결할 수 있다.
이 클래스는 std::basic_string_view 클래스 템플릿의 인스터스로서 <string_view> 헤더에 정의돼 있다.
string_view는 실제로 const string& 대신 사용할 수 있으며 오버헤드도 없다.
다시 말해 스트링을 복사하지 않는다.
string_view의 인터페이스는 c_str()이 없다는 점을 제외하면 std::string과 같다. data()는 똑같이 제공된다.
string_view는 remove_prefix(size_t)와 remove_suffix(size_t)라는 메서드도 추가로 제공하는데, 지정한 오프셋만큼
스트링의 시작 포인터를 앞으로 당기거나 끝 포인터를 뒤로 미뤄서 스트링을 축소하는 기능을 제공한다.
참고로 string과 string_view를 서로 연결/결합할 수 없다.
예를 들어 다음과 같이 작성하면 컴파일 에러가 발생한다.
string str = "Hello";
string_view sv = " world";
auto result = str + sv;
제대로 컴파일하려면 마지막 줄을 다음과 같이 수정한다.
auto result = str + sv.data();
다음에 나온 extractExtension() 함수는 주어진 파일명에서 확장자만 뽑아서 리턴한다.
참고로 string_view는 대부분 값으로 전달한다.
string_view extractExtension(string_view fileName)
{
return fileName.substr(fileName.rfind('.'));
}
함수를 이렇게 정의하면 모든 종류의 스트링에 적용할 수 있다.
string fileName = R"(c:\temp\my file.ext)";
cout << "C++ string: " << extractExtension(fileName) << endl;
const char* cString = R"(c:\temp\my file.ext)";
cout << "C string: " << extractExtension(cString) << endl;
cout << "Literal: " << extractExtension(R"(c:\temp\my file.ext)") << endl;
여기서 extractExtension()을 호출하는 부분에서 복제 연산이 하나도 발생하지 않는다.
extractExtension() 함수의 매개 변수와 리턴 타입은 단지 포인터와 길이만 나타내기 때문에 굉장히 효율적이다.
하지만 스트링의 길이를 이미 알고 있기 때문에 생성자에서 문자 수를 따로 셀 필요는 없다.
string_view를 사용하는 것만으로 string이 생성되지는 않는다.
string 생성자를 직접 호출하거나 string_view::data()로 생성해야 한다.
예를 들어 const string&을 매개변수로 받는 함수가 있다고 하면
void handleExtension(const string& extension) { /* ... */ }
이 함수를 다음과 같이 호출하면 제대로 작동하지 않는다.
handleExtension(extractExtension("my file.ext"));
제대로 호출하려면 다음 두 가지 방식 중 하나를 적용한다.
handleExtension(extractExtension("my file.ext").data()); // data() 메서드
handleExtension(string(extractExtension("my file.ext"))); // 명시적 ctor
2. std::string_view 리터럴
표준 사용자 정의 리터럴인 'sv'를 사용하면 스트링 리터럴을 std::string_view로 만들 수 있다.
auto sv = "My string_view"sv;
표준 사용자 정의 리터럴인 'sv'를 사용하려면 using namespace std::string_view_lite나
using namespace std;를 적어줘야 한다.
'💻프로그래밍 내용 정리 > C++17' 카테고리의 다른 글
[C++ 7.1.2] 메모리 할당과 해제(new, delete / malloc(), free()), nothrow (0) | 2022.08.22 |
---|---|
[C++ 7.1.1] 동적 메모리 작동 과정 살펴보기 (0) | 2022.08.22 |
[C++ 2.1.3-2] 하이레벨 숫자 변환(to_string, stoi), 로우레벨 숫자 변환(to_chars, from_chars) (0) | 2022.08.20 |
[C++ 2.1.3-1] C++std::string 클래스, 표준 사용저 정의 리터럴's' (0) | 2022.08.20 |
[C++ 2.1.2] 스트링 리터럴(리터럴 폴링, 로 스트링 리터럴, 확장 로스트링 리터럴) (0) | 2022.08.19 |