#include <string> // std::string 사용하기 위해 include
int main()
{
std::string a {}; // empty string
std::string b { "Alex" }; // "Alex"로 초기화
b = "Lewis Hamilton"; // "Lewis Hamilton"으로 수정. 길이 달라도 상관 없음
std::cout << b << '\n'; // std::cout으로 string 출력
int len { static_cast<int>(b.length()) }; // 문자열 길이
constexpr std::string c{}; // compile error
}
b의 경우 Alex에서 Lewis Hamilton으로 수정하여, 문자열의 길이가 더 길어졌으므로, 동적할당을 통해 알아서 더 긴 문자열을 저장해준다b.length()는 unsigned integer이므로 int형 변수로 받을 때는 casting을 해주어야 함string의 경우 constexpr 사용 불가능. std::string_view는 사용 가능#include <iostream>
#include <string>
void printString(std::string str) // str 초기화도 오래걸림
{
std::cout << str << '\n';
}
int main()
{
// 출력만 할 것이므로 string 사용하기엔 메모리, 시간 낭비
std::string s{ "Hello, world!" };
std::cout << s << '\n';
Print(s); // 역시 마찬가지
}
std::string은 초기화, 복사 등 과정이 오래 걸린다#include <iostream>
#include <string_view> // C++17
void printSV(std::string_view str) // string_view로 받기
{
std::cout << str << '\n';
}
int main()
{
std::string_view s{ "Hello, world!" }; // 초기화 및 복사 빠름
std::cout << s << '\n'; // "Hello, world!"
printSV(s); // 마찬가지
s = "Hi!"; // 포인터와 길이 정보만 바꾸어 저장
std::cout << s << '\n'; // "Hi!"
return 0;
}
string과 달리 문자열 데이터의 수정 불가능. 따라서 동작은 짧게 걸림(성능 향상)string_view 사용하는 것이 효율적void printString(std::string str) // string으로 받기
{
std::cout << str << '\n';
}
int main()
{
// string_view는 호환성이 좋다
std::string_view sv1 { "Hello, world!" }; // 리터럴로 초기화 가능
std::string s1{ "Hello, world!" };
std::string_view sv2 { s1 }; // string으로 초기화 가능
std::string_view sv3 { s2 }; // string_view로도 초기화 가능
// string으로의 변환은 명시적 변환만 가능
printString(s3); // compile error: 암시적 변환이므로 에러
std::string s2{ sv3 }; // 명시적 변환이므로 가능
printString(s2); // s2는 string이므로 가능
printString(static_cast<std::string>(sv)); // 명시적 변환이므로 가능
// constexpr 사용 가능
constexpr std::string_view sv4{ "Hello, world!" };
}
string_view는 뛰어난 호환성을 보이지만, string_view에서 string은 명시적 변환을 해주어야만 사용 가능하다 string과는 다르게 constexpr 사용 가능#include <iostream>
#include <string>
#include <string_view>
std::string getName() // 문자열 반환 함수
{
std::string s { "Alex" };
return s; // s는 값만 반환하고 메모리에서 사라짐
}
int main()
{
std::string_view sv{};
std::string s { "Hello" }; // string 선언
std::string_view sv { s }; // s 관찰
s = "Hi"; // s 수정
std::cout << sv << '\n'; // 에러 가능
sv = s; // 따라서 수정되었을 경우, 다시 설정해주기
// nested block
{
std::string str{ "Hello, world!" }; // nested block에서 생성
sv = str; // str를 참조
} // 이제 str은 소멸됨
std::cout << sv << '\n'; // 에러 발생 가능
std::string_view name { getName() }; // 반환값 s는 함수 종료되면서 사라짐
std::cout << name << '\n'; // 에러 발생 가능
using namespace std::string_literals;
std::string_view name { "Alex"s }; // string 리터럴로 초기화
std::cout << name << '\n'; // 에러 가능
}
string_view가 가리키는 문자열 데이터가 수정되거나 사라질 경우에는, 사용하면 안 됨 (dangling pointer)string literal은 메모리에서 일시적으로 존재하므로, 마찬가지로 string_view 사용이 불가능string_view의 초기화는 C style literal(그냥 "문자열"), string_view literal, string 이런 것들로 하기std::string_view foo1(bool b) // string_view로 반환
{
std::string t { "true" };
std::string f { "false" };
if (b)
return t; // 지역변수인 t를 관찰하는 string_view를 반환
return f; // 지역변수인 f를 관찰하는 string_view를 반환
} // 함수 종료되면 t, f는 사라짐
std::string_view foo2(bool b)
{
if (b)
return "true"; // "true"를 참조하는 view를 반환
return "false"; // "false"를 참조하는 view를 반환
} // "true", "false"는 안 사라짐
std::string_view foo3(std::string_view s1)
{
return s1;
}
int main()
{
std::cout << foo1(true) << foo1(false); // 에러 가능
std::cout << foo2(true) << foo2(false); // okay
std::string a { "Hello" };
std::cout << foo3(a); // okay
}
foo1이 호출되면, t, f를 관찰하는 string_view를 반환. t, f는 함수 종료되면 사라지므로 반환된 string_view에 문제 생길 수 있다.foo2에서는 C style literal을 참조하는 view를 반환. C style literal은 프로그램 끝날 때까지 남아있으므로 문제 없다.foo3에서는 caller에 존재하는 문자열(a)을 받아 관찰하는 view를 반환. 함수가 종료되어도 a는 남아있으니까 문제 없음view를 주로 사용한다string_view를 사용할 때 메모리에 존재하는 문자열인지 확인하며 사용해야 함view는 관찰하는 문자열의 포인터와, 길이 정보만을 저장 std::string_view str{ "Peach" };
// 앞 글자 제거
str.remove_prefix(1);
std::cout << str << '\n'; // each
// 뒷 글자 제거
str.remove_suffix(2);
std::cout << str << '\n'; // ea
str = "Peach"; // 다시 초기화
std::cout << str << '\n'; // Peach
str의 NULL도 사라짐. each\0 -> eaNULL로 끝내고 싶으면 string으로 변환시키면 된다to_string은 문자열로 만들어 반환하지만 임시객체를 반환
따라서 아래와 같이 사용할 경우 sv는 임시객체를 참조하고 있으므로 이 코드가 끝나면 이상한 값을 참조하게 됨
std::string_view sv {to_string("123")};
string으로 아예 객체를 생성해서 받아야 함std::string s {to_string("123")};
그럼 문자열을 정수형으로 바꾸려면 stoi()를 쓰면 된다
atoi()의 경우 char*를 인자로 받기 때문에 string 자료형을 사용할 수 없어, 대신에 stoi()를 사용
int n {stoi("-12345")};