string_view {C++17}
const string &
인자에 스트링 리터럴(const char *
)을 넣으면 string타입 객체를 암묵적으로 생성하기 때문에 비효율적이다. 따라서 string_view
타입이 나왔다.
string_view
는 문자열의 시작주소와 그 길이만을 저장하고 있기 때문에 string 인자에 비해 효율적이다. 또한 substr
연산도 또 다른 view를 리턴하기 때문에 문자열을 수정할 일이 없다면 이것을 쓰는 것이 좋다.
/**
* python-style string slicing
* str[start:end]
*/
std::string_view slice(std::string_view str, size_t start, size_t end) {
return str.substr(start, end - start + 1);
}
string_view는 string이 언제 소멸될지 알 수 없어 위험하다#
https://stackoverflow.com/questions/46032307/how-to-efficiently-get-a-string-view-for-a-substring-of-stdstring 에서 string_view가 UB를 낳는 시한폭탄이라는 평가가 있다.
사용예시#
https://leetcode.com/problems/longest-palindromic-substring 문제 풀이 소스. 파이썬이 개쩌는 언어라는 것을 다시 한 번 깨닫게 만들어주는 문제.
파이썬의 s[a:b]
문법은 C++에서 string_view{s}.substr(a, b - a + 1)
이다.
#include <string>
#include <cassert>
class Solution {
using sv = string_view;
sv expand(sv s, int left, int right) {
while (left >= 0 && right < s.size() && s[left] == s[right]) {
left--;
right++;
}
left++;
right--;
return s.substr(left, right - left + 1);
}
public:
string longestPalindrome(string s) {
if (s.size() == 1) {
return s;
}
string_view ret = s; // 'operator=' assgin 연산자도 가능!
ret = ret.substr(0, 1);
// 짝수 길이
for (int i = 0; i < s.size() - 1; ++i) {
auto palindrome = expand(s, i, i + 1);
if (palindrome.size() > ret.size()) {
ret = palindrome;
}
}
// 홀수 길이
for (int i = 0; i < s.size() - 2; ++i) {
auto palindrome = expand(s, i, i + 2);
if (palindrome.size() > ret.size()) {
ret = palindrome;
}
}
return string{ret};
}
};