[C#] StringBuilder

WestCoast·2022년 5월 26일
0

C#

목록 보기
1/2

MSDN - StringBuilder


아래 설명은 MSDN의 열받는 번역체를 조금 더 다듬은 내용입니다.

  • String, StringBuilder 둘 모두 문자열을 다룰 수 있게 도와주지만 세부 구현은 다릅니다. String 은 기본적으로 변경할 수 없는 형식(불변객체)입니다. 즉, String 객체를 수정하는 것처럼 보이는 각 작업들은 사실 새 문자열을 만드는 것과 같습니다.

  • 광범위한 문자열 조작(예: 루프에서 문자열을 여러 번 수정하는 앱)을 수행하는 루틴의 경우 문자열을 반복적으로 수정하면 상당한 성능 저하가 발생할 수 있습니다.
    대안은 변경 가능한 문자열 클래스인 사용 StringBuilder입니다.

  • 가변성은 클래스의 인스턴스가 만들어지면 문자를 추가, 제거, 바꾸기 또는 삽입하여 수정할 수 있음을 의미합니다.
    StringBuilder 개체는 문자열에 대한 확장을 수용하기 위해 버퍼를 유지 관리합니다.

  • 버퍼에 공간이 남은 경우 : 새 데이터가 버퍼에 추가됩니다.
    버퍼가 가득 찬 경우 : 더 큰 크기의 새 버퍼가 할당됩니다. -> 기존 버퍼의 데이터(문자열)을 새 버퍼에 복사합니다.


string


  • String은 불변객체라고 볼 수 있다.
    const char* str = "hello world"; 이와 같은 상수 문자 포인터가
    string str = "hello world"; string 구현의 기본 토대가 된다.
    그러니까, str의 "hello world"라는 문자열은 바꿀 수가 없는 것이다.

  • 엥? str = "bye bye"; 이러면 되잖아? 라는 질문을 할 수 있지만, 사실 이건 문자열 값을 수정하는 것이 아니다. 이런 수정은 아래처럼 동작한다.

    1. const char* 는 포인터 주소는 변경할 수 있지만, 포인터가 가리키는 실제 값은 수정할 수 없다.
    2. 그럼 새로운 const char* temp = "bye bye"; 를 할당한다.
    3. str = temp; 를 통해 str의 포인터 주소를 변경해준다.
  • 그러니까 위와 같은 과정에서 새로운 메모리를 할당하고, 기존 string에 새로 할당하는 등의 오버헤드가 포함되어 있는 것이다.
    참고로 str += "append" 같은 동작을 해도 위와 비슷하게 동작한다.


StringBuilder


  • 결국 위에서 설명한 문제를 해결하기 위해 StringBuilder가 취하는 방식은 간단하다.

    애초에 문자열을 담아놓을 공간을 크게 잡아놓으면 문제가 없잖아?

  • 이 '공간'이 MSDN에서 말하는 버퍼다. 그리고 이 버퍼는 가변객체인 것 같다.(정확하지 않음)

  • 기본적으로 StringBuilder sb = new StringBuilder(); 를 통해 할당해주면 버퍼의 크기(Capacity)는 16이다.

  • Capacity와 문자열의 길이는 다르다.
    예를 들어 Capacity는 사과 상자의 크기이고, sb.Length는 담은 사과의 갯수와 같다.

  • 버퍼가 가득 찰 때까지는 문자열을 조작해도 메모리 재할당이 일어나지 않는다.(string보다 오버헤드가 적다는 뜻)

  • 문자열의 길이가 16을 '초과'하는 순간 Capacity는 약 2배로 늘어난다.
    문자열의 길이가 32를 또 초과하면 다시 2배 늘어난다.(반복)

  • 하지만 이 Capacity가 커지는 순간 더 큰 블록의 메모리를 찾아서 재할당하므로 이 때는 오버헤드가 발생한다.


예제 코드


    class Program
    {
        static void Main(string[] args)
        {
            StringBuilder sb = new StringBuilder();
            Console.WriteLine("sb: {0}", sb);
            Console.WriteLine("Length: {0}, Capacity: {1}\n", sb.Length, sb.Capacity);

            for (int i = 0; i <= 16; i++)
                sb.Append("a");
            Console.WriteLine("sb: {0}", sb);
            Console.WriteLine("Length: {0}, Capacity: {1}\n", sb.Length, sb.Capacity);

            for (int i = 0; i <= 15; i++)
                sb.Append("b");
            Console.WriteLine("sb: {0}", sb);
            Console.WriteLine("Length: {0}, Capacity: {1}\n", sb.Length, sb.Capacity);
        }
    }

출력

sb:
Length: 0, Capacity: 16

sb: aaaaaaaaaaaaaaaaa
Length: 17, Capacity: 32

sb: aaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbb
Length: 33, Capacity: 64
profile
게임... 만들지 않겠는가..

0개의 댓글