C++ 프로그래밍

C++ string_view의 이해와 활용

하늘흐늘 2022. 1. 15. 20:33
반응형

string_view는 C++ 17에 추가된 클래스로 문자열에 대한 참조라고 볼 수 있습니다. 사용법은 string과 유사하며 장점은 string에 비하여 적은 메모리 사용량과 연산 성능에 대한 이점을 가지고 있습니다. 단점은 잘못된 사용시 임시 객체 사용에 따라 참조가 없어져 예상치 못한 에러가 발생할 가능성이 있으며 내부구조가 널로 종료하는 문자열을 참조하지 않는 관계로 널로 종료하는 문자열을 필요로하는 C API와 같은 함수에 사용할 수 없다는 점 등이 있습니다. 참고로 string_view는 가볍다는 장점을 바탕으로 몽고DB C++ 드라이버에서는 벌써 적절하게 사용하고 있습니다.

이 글에서는 string_view의 특성, 사용법, 장점 및 단점을 살펴보도록 하겠습니다.

string_view 특성
string_view는 문자열에 대한 참조를 가질 뿐 내용을 가지지 않는 참조 객체입니다. 이런 특성을 가진 관계로 string_view를 사용하기 위해서는 string_view가 참조하는 원본 문자열이 메모리상에 존재하여야 합니다. 원본 문자열이 존재하지 않을 경우 string_view는 예상치 못한 오류를 발생시키게 됩니다. 이외에 참조만을 가지는 객체지만 string가 유사한 대부분의 연산을 지원합니다.


string_view 사용법

string_view의 할당은 아래와 같이 할 수 있습니다.

string str1 = "test1";
string_view sv1(str1);
string_view sv2 = str1;
string_view sv3 = "test2";


함수 인자로 사용시 string과 char *를 모두 받을 수 있습니다.

auto func1 = [](string_view sv_arg)
{
	cout << sv_arg << endl;
};

string str2("test2");
func1(str2);
func1("test3");


전반적인 사용법은 아래와 같이 string과 유사합니다.

string str4("test6");
string str5("test7");
string_view sv4(str4);

if (sv4 == str5)
{
	cout << "sv4 == str5" << endl;
}
else
{
	cout << "sv4 != str5" << endl;
}

if (sv4 == "test6")
{
	cout << "sv4 == \"test6\"" << endl;
}


마지막으로 string_view를 string으로 대입하는 방법은 아래와 같습니다.

string_view sv5 = "test8";
string str6(sv5);
string str7;
str7.assign(sv5);

 

string_view 장점
string_view은 문자열에 대한 참조인 관계로 사용할 수 있는 상황에서 string을 사용하는 것에 비하여 적은 메모리를 사용하며 연산상 성능 향상의 이점이 있습니다. string_view와 string의 성능 비교는 Performance of std::string_view vs std::string from C++17를 참조하시면 됩니다.


string_view 단점

문자열에 참조인 관계로 원본 문자열이 메모리 상에 존재하지 않으면 예상치 못한 문제가 발생합니다. 

예로 아래와 같은 코드는 이상없이 test9를 출력합니다.

string str8 = "test9";

vector<string_view> test_vec1;
test_vec1.push_back(str8);

cout << test_vec1[0] << endl;

하지만 아래와 같은 코드는 test10이 아닌 예상치 문자열을 출력합니다.

string str9 = "test10";

vector<pair<int, string_view>> test_vec2;
test_vec2.push_back(make_pair(1, str9));

for (auto iter : test_vec2)
{
	cout << iter.first << endl;
	cout << iter.second << endl;
}

이는 중간에 생성되는 임시 객체로 인하여 최종 객체의 참조가 잘못되기 때문입니다.

마지막으로 string의 c_str()처럼 string_view는 data()라는 참조하고 있는 버퍼에 대한 포인터를 리턴합니다.

string_view sv6 = "test11";

cout << sv6.data() << endl;

하지만 이 data() 함수의 리턴값은 C++ 표준에 따르면 널로 끝나는 문자열이 아닌 관계로 널로 끝나는 문자열을 필요로 하는 C API와 같은 함수에서는 사용해서는 안됩니다. 물론 C++ string_view의 구현에 따라 널로 끝나는 문자열을 리턴하는 경우도 있지만 표준에서 널로 끝나는 문자열이 아닌 관계로 호환성이나 차후 C++ 업데이트 등을 고려할 때 널로 끝나는 문자열을 필요로 하는 곳에서는 data()를 사용해서는 안됩니다.

 

 

 

반응형