전문가를 위한 C++

2025/02/24 ch02. 스트링과 스트링 뷰 다루기

딴짓거리 2025. 2. 24. 18:43

로우 레벨 숫자 변환

<charconv> 헤더에 정의되어 있다.

메모리 할당에 관련된 작업은 전혀 해주지 않고 string도 직접 다루지 않기 때문에 호출한 측에서 로 버퍼(원시 버퍼)를 할당하는 방식으로 사용해야 한다.

고성능과 로케일 독립성에 최적화되었다.

(로케일독립성 - 나라마다 숫자를 표기하는 방식이 다를 수 있는데, 항상 같은 결과를 보장해줌)

하이레벨 숫자 변환 함수에 비해 처리 속도가 엄청나게 빠르다

퍼펙트 라운드 트리핑 방식으로 설계되었다. - 숫자값을 스트링 형태로 직렬화 한 뒤, 그 결과로 나온 스트링을 다시 숫자값으로 역직렬화 하면 원래 값이 나온다.

(부동소수점 숫자를 문자열로 변환했다가 다시 숫자로 변환했을때 특성상 아주 조금의 오차가 발생할 수 있지만 그렇지 않다는 뜻)

숫자 데이터와 사람이 읽기 좋은 포맷 사이의 변환 작업을 로케일에 독립적이고 퍼펙트 라운드 트리핑을 지원하면서 빠른 속도로 처리하고 싶다면 이런 로우레벨 함수를 사용

 

숫자를 스트링으로 변환

정수를 문자로 변환하려면?

to_chars_result to_chars(char* first, char* last, IntegerT value, int base = 10);
// IntergerT <- 부호있는정수, 없는 정수, char

struct to_chars_result{
	char* ptr;
    errc ec;
};

 

부동소수점도 지원한다

기본 포맷인 chars_format::general을 적용하면 to_chars()는 부동소수점값을 십진수 표기법인 (-)ddd.ddd와 십진수 지수 표기법인 (-)d.ddde+-dd 중에서 소수점 왼쪽에 나오는 숫자를 표기할 때 전체 길이가 가장 짧은 형태로 변환된다.

포맷에 정밀도(precision)를 지정하지 않으면 주어진 포맷에서 가장 짧게 표현할 수 있는 형태로 결정된다.(정밀도의 최대값은 여섯자리)

 

스트링을 숫자로 변환

 

 

std::string_view 클래스

읽기 전용 스트링을 받는 함수의 매개변수 타입?

const char* // string을 사용하려면 c_str() 혹은 data() 로 직접 구해야함.
//std::string의 편리한 메서드를 사용할 수 없음

const std::string& // 항상 std::string을 사용해야 한다.
//스트링 리터럴을 전달하면 스트링 리터럴의 복사본이 담긴 string객체를 생성해서 함수로 전달하므로
//오버헤드가 발생함

 

<string_view>
std::string_view

const string& 대신 사용할 수 있으며 오버헤드도 없다. 스트링을 복사하지 않음

string과 거의 동일하게 사용할 수 있다.

 

string_view를 사용하는 것만으로는 실제 string이 생성되지는 않으니 주의

string 생성자를 직접 호출하거나, string_view::data() 멤버로 생성해야 한다.

 

스트링을 리턴하는 함수는 반드시 const string&나 string 타입으로 리턴해야 한다.

string_view로 리턴하면 결과를 보장할 수 없다.

 

클래스의 데이터 멤버를 const string&, string_view로 저장하려면 이들이 가리키는 스트링이 객체의 수명 동안 살아있도록 보장해야한다. string으로 저장하는 것이 안전하다.

 

임시 스트링에 대한 뷰를 저장하는 용도로 사용하면 안된다

string s { "Hello" };
string_view sv { s + " World!" }; // "Hello World!"라는 임시 스트링이 생성되고 sv가 그 임시 스트링을 가리키게 됨
cout<<sv; //임시 스트링이 삭제되어 결과를 보장할 수 없음

 

 

C++20

스트링 포맷 지정

<format>에 정의된 std::format()으로 스트링의 포맷을 지정할 수 있다.

format("포맷 지정 스트링", 에 있는 빈칸에 채워질 값);

string t1 = "Hello";
string t2 = "World";

format("{}, {}", t1, t1); //Hello, World
format("{0}, {1}", t1, t2); //순서를 직접 정해줄 수 있다. 결과는 같음
format("{1}, {0}", t1, t2); // World, Hello  <- 간편하게 순서를 바꿀수 있다

 

포맷 지정자

width - 주어진 값의 포맷을 적용할 필드의 최소 폭을 정한다.

[fill]align - 채울 문자와 해당 필드에 값이 정렬되는 방식을 지정한다.

sign 

# - 얼티네이트 포매팅 규칙을 제공. 0x 0X 0b 0B 등을 숫자 앞에 붙여 각종 진수로 표현

type - 주어진 값을 반드시 따라야 할 타입을 지정

 

precision - 부동소수점, 스트링 타입에만 적용됨

부동소수점 - .(점)을 붙이고 그 뒤에 10진수 숫자를 적음

스트링 - 점 뒤에 문자 개수를 적음

width와 마찬가지로 중괄호로 표기 가능. 동적 정밀도라고 부른다

 

0 - width로 만든 공백에 0을 채운다

 

출력 형식을 꾸밀 수 있으니 편하다

 

이러한 포맷지정자를 잘못 사용하면 std::format_error 익셉션을 던진다

 

커스텀 타입 지원

c++20 포맷 지정 라이브러리는 커스텀 타입에 대해 확장할 수 있다.

formatter 클래스 템플릿을 특수화 해야함

parse(), format() 두 가지 메서드 템플릿을 제공

지나치게 어려운 내용이라 12장에서 다시 설명..

 

 

~203p