Information Technology/C++

[C++] std::string의 여러가지 생성자들과 형변환

이웃어 2019. 12. 7. 11:06

이 글은 개인의 학습을 목적으로 정리한 글입니다. 이점 참고하고 읽어주세요 ;)


이번 포스팅에서는 std::string을 사용하는 생성자와, 다른 자료형과 string의 형변환에 대해 다뤄보겠습니다.

#include <iostream>
#include <string>
#include <vector>

int main()
{
	std::string my_string;			// default 생성자
	std::string my_string2("MY STRING");	// 값을 주는 생성자
    	std::string my_string3(my_string2);		// 복사 생성자

	std::cout << my_string << std::endl;	// 아무런 문자열도 출력하지 않음
	std::cout << my_string2 << std::endl;	// "MY STRING" 출력
    	std::cout << my_string3 << std::endl;	// "MY STRING" 출력

	return 0;
}

우선 아주 기본적인 std::string의 생성자 사용법입니다. my_string처럼 아무런 값도 주지 않고 인스턴스를 생성하면 default 생성자를 호출하기 때문에 my_string에는 아무런 값도 저장되지 않습니다.

그리고 my_string2처럼 문자열을 생성자에 입력하면 코드와 같이 "MY STRING"이라는 문자열이 my_string2에 저장됩니다.

또는 my_string3처럼 다른 string 클래스의 인스턴스를 대입하여 복사 생성자를 호출할 수도 있습니다.

 

std::string은 10가지가 넘는 생성자를 가지고 있습니다. 그중 몇 가지만 간단히 다뤄보겠습니다.


const char* my_string = "my string";		// C-스타일의 문자열 저장
std::string second_char(my_string, 3, 5);	// 생성자의 입력값으로 C-스타일 문자열 변수도 가능
// 출력: string

위에 입력한 생성자는 입력받은 문자열에서 특정 부분만 가져오는 생성자입니다.

눈치챈 분들도 계실 텐데, 첫 번째 매개변수로 받은 문자열 중에서 두 번째 매개변수로 받은 숫자만큼의 문자열을 지운 다음, 그다음 문자열부터 세 번째 매개변수로 받은 숫자만큼의 문자열을 출력하는 생성자입니다.

위의 예제에서는 입력받은 "my_string"이라는 문자열 중 앞의 3개를 지우고 4번째 문자열부터 5개를 출력하니

"my_"가 지워지고 그다음부터 5개의 문자열인 "string"이 출력됩니다.


std::string my_string(10, 'A'); // A를 10개 저장
std::cout << my_string << std::endl; // "AAAAAAAAAA" 출력

std::string에는 원하는 문자열의 개수를 지정해서 저장하는 생성자도 존재합니다.

위와 같이 생성자의 첫 번째 매개변수로 숫자를 입력하고, 그다음 매개변수에 문자를 입력하면 위의 코드 블록과 같이 입력한 문자열이 원하는 개수만큼 저장됩니다.


int main()
{
	std::vector<char> vec;
	for (auto e : "Today is a good day")
		vec.push_back(e);
	
	std::string second_string(vec.begin(), vec.end());
	std::cout << second_string << std::endl; // "Today is a good day" 출력

	return 0;
}

이번에는 std::vector를 사용해서 std::string에 문자열을 저장해보겠습니다.

우선 아무런 정보도 저장되지 않은 vector를 vec라는 이름으로 초기화해준 다음,

for-each문으로 vector의 push_back을 통해 "Today is a good day"라는 문자열의 각 문자들을 vec에 저장해줍니다.

그다음 std::string을 통해 second_string을 생성하면서,

첫 번째 매개변수로 가져올 vector 인스턴스의 시작 값을, 두 번째 매개변수로 vector 인스턴스의 마지막 값을 입력하면 second_string에도 vec에 담긴 처음부터 마지막까지의 문자열이 그대로 저장됩니다.


int main()
{
	std::vector<char> vec;
	for (auto e : "Today is a good day")
		vec.push_back(e);
	
	std::string second_string(vec.begin(), std::find(vec.begin(), vec.end(), ' '));
    // vec의 시작부터, vec에서 처음부터 끝까지 중 처음으로 ' '(공백)이 나오는 곳까지 찾아서 저장
	std::cout << second_string << std::endl;

	return 0;
}

위와 같은 방식도 있습니다.

똑같이 std::vector를 사용하는데, 이번에는 std::find()를 통해 자신이 원하는 문자열이 있는 위치까지만 출력을 하는 방식입니다.

두 번째 매개변수로 사용한 std::find()를 간단히 설명하면

첫 번째 매개변수에 자신이 찾을 문자열이 저장된 배열(혹은 벡터)에서 탐색을 시작할 위치를,

두 번째 매개변수에 탐색을 끝낼 위치를,

마지막인 세 번째 매개변수에 자신이 찾을 문자열을 입력하면 됩니다.

저도 자세히 아는 분야는 아니지만, 머신 러닝에 필요한 데이터들 역시 분석 이전에 데이터들을 적절하게 전처리해주는 과정이 필요한데, 그럴 때 매우 유용하게 사용될 것 같습니다.


// std::string my_str(4); // error 발생!
std::string my_str(std::to_string(4));
std::cout << my_str << std::endl; // string 자료형의 '4' 출력

이번에는 std::string에 문자열이 아닌 다른 자료형을 저장하는 방법입니다.

std::stirng에 일반 문자열을 입력하듯이 생성자에 그대로 int, float, double 등의 자료형을 입력해주면 std::string은 이를 받아들이지 않고 에러를 발생시킵니다. 사용자 입장에서는 그냥 입력받은 다른 자료형도 적당히 알아서? string 자료형으로 바꿔주면 되지 않겠느냐 생각할 수도 있지만, 깐깐한 C++은 그걸 허용하지 않는다고 합니다.

이 문제를 해결하려면 std::to_string()을 사용하면 됩니다. 사용법은 간단하게 std::to_string()에 사용할 자료형의 데이터를 입력해주면 됩니다.

다만 이렇게 저장되고 출력되는 데이터는 stirng 자료형으로 변환된 문자열로서의 데이터입니다.

	std::string my_str(std::to_string(4));
	my_str += std::to_string(128);
	std::cout << my_str << std::endl; //"4128" 출력

간단한 응용?으로 my_str에 덧셈 연산자를 사용해서 to_string으로 변환한 "128"을 더해주면 "4128"이 출력됩니다.


그렇다면 string 자료형의 데이터를 int, float 등등의 자료형으로 변환하는 방법은 없을까요? 당연히 존재합니다.

	std::string my_str(std::to_string(4));
	float i = std::stof(my_str);

	std::cout << my_str << std::endl; // string 자료형의 "4" 출력
	std::cout << i << std::endl;	  // float 자료형의 4 출력

방법은 std::stof() 사용하면 됩니다. stof는 string to float의 줄임말이라고 생각하면 될 것 같습니다.

이 코드 블록에서는 string 자료형을 float 자료형으로 변경해서 std::stof를 사용했고,

만약 int 자료형으로 바꾼다면 std::stoi를, double 자료형이라면 std::stod 등 알맞은 std를 찾아서 사용하면 됩니다.


#include <iostream>
#include <string>
#include <vector>
#include <sstream> // string stream

template<typename T>
std::string Tostring(T x)
{
	std::ostringstream osstream; //output string stream
	osstream << x; 			    // 전달인자 x가 osstream으로 들어감
	return osstream.str(); 	    // string으로 바꿔서 리턴
}

int main()
{
	std::string my_str(Tostring(3.14159));
	std::cout << my_str << std::endl;	// string 자료형의 "3.14159" 출력
	return 0;
}

<sstream>을 이용해서 사전 정의된 자료형을 string 자료형으로 형변환해주는 방법도 있습니다.

<sstream>은 string stream의 줄임말로 string 입출력에 관한 라이브러리입니다.

 

다양한 자료형을 string으로 바꿔주기 때문에 함수 선언 앞에 template 선언을 해줍니다.

함수의 출력 자료형은 std::string, 함수의 이름은 Tostring이라고 정하고 매개변수로 템플릿 자료형의 x를 받습니다.

그리고 함수 내에 std::ostringstream 자료형의 osstream을 만들어줍니다.

ostringstream이란 output string stream, 즉 string stream의 출력 자료형 정도로 생각하면 될 것 같습니다.

그리고 매개변수로 받은 x를 osstream 변수에 저장하고, osstrema.str()을 사용하면 매개변수로 들어온 x가 string 자료형으로 형변환 되어 리턴됩니다.

이를 main 함수에서 그대로 사용하면 Tostring 함수에 전달인자로 준 값이 string 자료형으로 출력되는 걸 볼 수 있습니다.


이번에는 FromString이라는 함수를 통해 string 자료형 변수에 저장된 값을 원하는 자료형으로 형변환하는 방법을 알아보겠습니다.

template<typename T>
bool FromString(const std::string& str, T& x)
{
	std::istringstream isstream(str);	    // isstream을 매개변수 str로 초기화
	return (isstream >> x) ? true : false;	    // isstream에 저장된 값을 T 자료형인 x로 보냄
}

FromString 함수는 Tostring 함수와 반대로 string 자료형을 모든 자료형으로 형변화해야하기 때문에 역시 template 선언을 해줍니다.

그리고 형변환이 성공했는지 여부를 나타내기 위해 리턴 타입은 bool 자료형으로 정하겠습니다.

함수 내부에는 std::istringstream 자료형의 인스턴스를 isstream이라는 이름으로 선언하고 매개변수로 받는 str로 초기화해줍니다. istringstream은 input string stream의 약자로 stirng 자료형을 입력받는 클래스입니다.

그리고 리턴 값으로는 isstream에 저장된 string 자료형의 데이터를 두 번째 매개변수인 x에게 보내줍니다.

만약 str에 저장된 값이 x의 자료형인 T로 형변환된다면 true를 리턴하고, 실패한다면 false를 리턴합니다.

int main()
{
	std::string my_str(Tostring(3.14159));
        std::string my_str2("Hello");
	double d;

	if (FromString(my_str, d))
		std::cout << d << std::endl;
	else
		std::cout << "Cannot convert" << std::endl; // 3.141592 출력

	if (FromString(my_str2, d))
		std::cout << d << std::endl;
	else
		std::cout << "Cannot convert" << std::endl; "Cannot convert" 출력
        
	return 0;
}

main 함수에서는 위와 같이 사용합니다. Tostring 함수를 통해 string 자료형 변수 my_str을 만들고,

"Hello"라는 문자열로 초기화된 my_str2를 만들어준 다음

double 자료형 인스턴스 d를 만들어줍니다.

그리고 my_str과 d를 매개변수로 준 FromString 함수를 if-else문의 조건으로 줍니다.

만약 FromString 함수에 의해 형변환이 성공적으로 일어난다면 그대로 d의 값을 출력하고,

그렇지 않다면 형변환에 실패했다는 문구를 출력하도록 설정했습니다.

my_str에 저장된 "3.141592"라는 문자열은 숫자이기 때문에 double 자료형으로 성공적으로 형변환이 됩니다.

하지만 my_str2에 저장된 "Hello"라는 문자열은 double 자료형으로 형변환될 수 없기 때문에 "Cannot convert"라는 문자열을 출력합니다.


std::string과 관련해서 이런저런 내용을 다뤘습니다. 중간에 <sstream>까지 등장하면서 내용을 정리하는 지금도 내용이 머릿속에서 잘 정리가 되지 않는데,

stream과 관련된 내용은 다음 포스팅에서 더욱 자세하게 다루겠습니다.