백준/이걸 몰랐네

std::string 빈 문자열에 값 대입하는 방법

발전생 2020. 8. 27. 23:52

오늘 2차원 문자 배열 문제를 풀면서 삽질 참 여러번 했다.

 

이전 같으면 그냥 char 타입을 담는 배열의 배열을 만들었겠지만 이번엔 좀 다른 시도를 해보고 싶었다.

그래서 string 타입을 담는 배열로 만들어봤는데 에러가 떴다.

std::string arr[8];

for(int i=0; i<8; i++) {
	for(int j=0; j<8; j++) {
          if((i+j) %2 == 0) {
              arr[i][j] = 'B';
          } else {
              arr[i][j] = 'W';
          }
    }
}

 

그래서

arr[i] = "WBWBWBWB";

이런 식으로 string 변수에 그냥 문자열을 통째로 넣어주는 식으로 해결했다.

문자 하나하나 string 변수에 넣고 싶으면 arr[i].push_back('W') 이런 식으로 가능하다.


그렇다면 string 타입 변수는 operator[]로 주소에 접근이 불가능한 걸까?

NO

 

혹시 몰라 테스트를 해봤는데 이건 에러 없이 잘 작동한다.

string test_s[3] = { "abc", "def", "ghi" };
test_s[0][0] = 'F';
cout << test_s[0];

string 타입 원소의 원하는 인덱스에 값을 넣었다. 이게 가능하다.

 

string 타입 변수도 다른 변수와 마찬가지로 operator[]를 통해 주소에 접근해서 값을 변경할 수 있다.


그럼 왜 위에서는 에러가 뜬 걸까?

 

일단 arr 각각의 원소(string 타입)은 capacity는 기본 15로 할당되어있지만 size는 0이다.

한줄한줄 디버깅을 통해 알아냈다. 

에러가 말해주길 범위 밖에 접근했단다.

 

cpp reference를 보니 빈 string를 생성하면 size 0이고 begin과 end가 같은 상태이다.

의도치 않은 것들이 메모리에 차있을텐데 size 0인 상태에서 원소에 접근 가능하다면 그것도 위험한 일일 것이다.

 

정확히 어떻게 작동하는가?

std::basic_string의 operator[]를 살펴봤다.

(1)	reference operator[]( size_type pos );
(2)	const_reference operator[]( size_type pos ) const;

c++20 까지는 이렇게 정의되어 있다.

정의만 봐서는 "reference 타입 리턴하면 값 바꿀 수 있잖아?" 이런 생각이 든다.

 

If pos == size(), a reference to the character with value CharT() (the null character) is returned.
For the first (non-const) version, the behavior is undefined if this character is modified to any value other than CharT() .

If pos > size(), the behavior is undefined.

c+11부터는 이렇게 된다고 설명이 되어있다.

해석해보면

pos==size()일 때 const_reference 리턴 타입이면 널 문자 값을 가지는 문자의 레퍼런스를 리턴한다.
reference 리턴 타입이면(다른 값으로 수정하려고 하면) 어떻게 할지 정의가 안되어있다.

pos > size()이면 역시 어떻게 할지 정의되어 있지 않다.

 

오류가 났던 코드에서 맨 처음에는 size가 0인 string에게 매개변수 pos 값으로 0을 넘겨준다.

pos==size() 상황인데 const_reference 타입을 리턴하면 값을 바꿀 수가 없다.

reference 타입을 리턴한다면 좋을텐데 값을 수정하려고 하면 함수 내용이 없다. 당연히 의미 있는 리턴도 없다.

그러니 빈 string에 인덱스로 접근해서 값을 바꿀 수가 없었던 거다.

 

 

참고로 int 배열은 빈 배열이어도 임의의 원소에 접근해 값을 바꾸는 게 가능하다.

int main() {
    int arr[4];
    arr[0] = 3;
    
    cout << arr[0];
}

정리

 

빈 string의 인덱스 주소에 접근해 값을 변경하는 건 불가능하다.

빈 string에 값을 넣으려면 문자열을 대입하거나 push_back()으로 문자 하나씩 넣어야 한다.


인용

https://en.cppreference.com/w/cpp/string/basic_string