프로그래밍 공부
작성일
2024. 1. 12. 17:43
작성자
WDmil
728x90

2.1.3 C++ string 클래스

 

C++는 표준 라이버리를 통해 훨씬 진보된 문자열을 제공한다.

 

C++의 std;:string 클래스는 <cstring>에서 제공하는 문자열 처리 기능을 대부분 지원하면서, 제대로만 사용한다면 메모리 할당 부분까지 대신 관리해준다.

 

string 클래스는 <string> 헤더 파일에 정의되어 있다.


C스타일 문자열의 문제점

C++ strnig의 필요성을 이해하려면, C스타일 문자열의 장점과 단점을 알아야 한다.

장점

  • 단순하다. 기본문자 타입과 배열구조만 사용한다.
  • 가볍가. 제대로 사용하면 꼭 필요한 메모리 공간만 점유한다.
  • 저수준이다. 로우 메모리상에서 쉽게 조작하거나 복제할 수 있다.
  • C 프로그래머에게 매우 익숙하다.

단점

  • 범용 문자열 데이터 타입이므로 고급 작업을 하기에는 너무 많은 노력이 추가로 필요하다.
  • 잘못된 메모리 작업에 민감하고 해당 버그를 찾기 어렵다.
  • C++ 객체지향 개념을 활용하지 못한다.
  • 프로그래머가 문자열 내부 동작방식을 이해해야 한다.

string 클래스 사용법

 

string이 클래스 이기는 하지만, 대부분은 int나 char같은 내장 기본타입으로 취급하고, 사용해도 아무런 문제가 없다.

 

사실 string이 객체라는 사실을 잊어버리면 문제가 발생할 가능성이 더 줄어든다.

 

연산자 오버로딩이 부리는 마법 때문에 C++ strinf은 C의 문자열보다 이용하기 더 쉽다.


문자열 덧붙이기

string은 다음과 같은 문자열 덧붙임을 지원한다.

strign A("12");
string B("34");

string C;

C = A + B; // C 는 '1234'가 됨
A += B; // A는 '1234'가 됨

 


문자열 비교하기

 

C에서는 문자열을 비교하기 위해서는 strcmp를 사용해야 하고, <나 <= > >= 와 같은 비교연산자도 못쓴다.

 

그래서 strcmp()함수는 사전적 순서에 기반하여 리턴값을 -1, 0, 1과같이 다르게 준다.

if(strcmp(a,b) == 0)

 

 

 C++의 string에서는 operator ==, != < 등의 연산자오버로딩을 수행하고 있다. operator[]도 오버로딩하기 때문에, 개별적으로 문자열에 접근할 수 있다.

 

string myString = "hello";
myString += ", there";
string myOtherString = myString;
if(myString == myOtherString) {
	myOtherString[0] = 'K';
}
cout << myString << endl;
cout << myOtherString << endl;

위와같은 모든 메모리관리, 연산자가 사용 가능하다.

그래서 문자열과 관련된 문제를 잊어버려도 무방하다.

 

위 코드가 진행되면서 알아야할 사실 몃가지가 있다.

 

문자열의 크기 변경과 신규 메모리 할당이 각각 좌항과 우항에서 발생하지만, 메모리 릭은 발생하지 않는다.

 

중간과정에서 생성되는 string 객체는 모두 스택에 생성되기 때문에, 메모리 크기 변경과 할당이 여러번 일어나더라도, 작업이 완료되고 스코프에서 벗어나는 순간, string의 소멸자가 호출되면서 모든 메모리가 정리된다.

 

연산자들이 프로그래머가 기대하는대로 작동한다.

 

예를들어 = 연산자는 모든 문자열을 복제한다.

만약 배열 기반의 문자열로 =를 하게되면, 주솟값이 대입되었기 때문에, 나중에 원본참조 문제가 발생할 수 있다.

 

하지만, string은 알아서 복제해준다.

 

호환성 때문에 string에서 C스타일의 const 문자열 포인터를 얻기 위해, c_str()메서드를 이용할 수 있다.

하지만, 리턴받은 const 포인터는 strirng 메모리를 재할당 하거나 string객체가 삭제되는 순간 무효됨으로 조심해야한다.

 

c_str()메서드는 C스타일을 사용해야하는 코드에서 바로 호출하여 최신 string 내용이 반영되도록 해야한다.

그리고, string이 스택에 할당되어 있다면, c_str()의 리턴값을 절대 그 함수 밖의 다른곳에 넘겨주어서는 안된다.


std:: string 리터럴

소스코드에서 문자열 리터럴을 사용하다보면 보통 const char* 타입으로 취급된다.

const char* 대신 std:;string으로 취급하게 하고싶다면, 다음과같이 s를 붙이고 사용하면 된다.

auto string1 = "Hello World";	// const char*
auto string2  = "Hello World"s;	// std::string

수치 변환

str 네임스페이스는 숫자와 string상호간의 변환을 편리하게 해주는 몇가지 함수를 추가로 제공한다.

string to_string(int val);
string to_string(unsigned val);
string to_string(long val);
string to_string(unsigned long val);
string to_string(long long val);
string tostring(unsigned long long val);
string to_string(float val);
string to_string(double val);
string to_string(long double val);

함수타입만으로도 쉽게 유추할 수 있다.

 

반대로, 문자열을 숫자로 변환하는 함수도 지원한다.

 

이 역시 std 네임스페이스에서 제공한다.

 

이 함수에서 파라미터 str은 변환할 string을 지정하고, 파라미터 idx는 변환에 실패한 첫 번째 문자의 인덱스를 리턴하고,

파라미터 base는 몇 진수(2, 10진수 등)로 변환할지 지정한다.

 

idx에 null을 넘겨서 에러위치를 넘겨받지 않을 수도 있다.

 

변환에 실패하면 invalid_argument 익셉션을 발생시키고, 변환한 숫자가 해당 숫자 타입의 표현 범위 밖이면 out_of_range익셉션 을 발생한다.

int stoi(const std::string& str, size_t* idx = 0, int base = 10);
long stol(const std::string& str, size_t* idx = 0, int base = 10);
unsigned long stoul(const std::string& str, size_t* idx = 0, int base = 10);
long long stoll(const std::string& str, size_t* idx = 0, int base = 10);
unsigned long long stoull(const std::string& str, size_t* idx = 0, int base = 10);
float stof(const std::string& str, size_t* idx = 0);
double stod(const std::string& str, size_t* idx = 0);
long double stold(const std::string& str, size_t* idx = 0);
728x90