Содержит ли StringBuilder, инициализированный строкой, достаточно (только) достаточно места для этой строки? - PullRequest
6 голосов
/ 15 февраля 2010

Мне интересно, если этот код ...

StringBuilder sb = new StringBuilder("Please read the following messages.");

... инициализирует sb буфером, точно таким же, как строка, переданная конструктору. С одной стороны, это казалось бы самым логичным. С другой стороны, кажется, что это своего рода поражение цели класса StringBuilder для одного из его наиболее распространенных применений, которое заключается в обеспечении изменчивости, чтобы сделать повторные добавления более эффективными. (Самый первый вызов Append, если ответ на мой вопрос «да», потребует sb для изменения размера.)

Опять же, я полагаю, можно было бы рассматривать это как аналог конструктора для List<T>, который принимает IEnumerable<T> в качестве параметра. Возможно, в этом случае предполагается, что вы не планируете добавление много, а скорее манипулирование тем, что уже есть.

Единственным реальным исследованием, которое я провел по этому вопросу, была проверка документации MSDN на StringBuilder , которая не дала ответа (он говорит, что конструктор инициализирует экземпляр «используя указанную строку»). но не указывает, как используется строка).


РЕДАКТИРОВАТЬ : Так что это "зависит от реализации" ... никому это не кажется странным? Я имею в виду, что цель класса StringBuilder - предложить альтернативу выполнению большого количества операций над string, создавая массу неизменных string экземпляров на этом пути; следовательно, это для эффективности . Мне кажется, что поведение этого конструктора должно быть определено, чтобы разработчик мог принять взвешенное решение о том, как его использовать, независимо от платформы.

Я имею в виду, что является реализованным Microsoft определенным образом; они могли бы легко поместить это в документацию (заставив другие реализации последовать их примеру). Просто личный источник недоумения ...

Ответы [ 4 ]

5 голосов
/ 15 февраля 2010

Это деталь реализации, о которой вам не нужно беспокоиться.Однако, используя .NET рефлектор и просматривая перегрузку (string, int32, int32, int32) конструктора (который вызывают другие конструкторы), мы можем видеть, что он выбирает емкость, кратнуюиз 16 (следующий по величине после запрошенного размера)

Редактировать

На самом деле, это 16 x 2 ^ n, со значением "n", выбранным следующимсамый большой размер

4 голосов
/ 15 февраля 2010

Проверьте элемент Capacity StringBuilder.

С MSDN :

StringBuilder динамически распределяет больше места при необходимости и соответственно увеличивает емкость. По соображениям производительности StringBuilder может выделять больше памяти, чем необходимо. Объем выделяемой памяти зависит от реализации.

2 голосов
/ 15 февраля 2010

Конструктор, с которым вы связались, вероятно, связан с StringBuilder(String, Int32, Int32, Int32):

public StringBuilder(
  string value,
  int startIndex,
  int length,
  int capacity
)

Итак, для строки она, вероятно, будет проходить через: string, 0, string.Length, string.Length. Или нечто подобное, имеющее смысл в контексте StringBuilder.

1 голос
/ 15 февраля 2010

В итоге вызывается конструктор:

// "Please read the following messages.".Length = 35
public StringBuilder(string value, int startIndex, int length, int capacity)
public StringBuilder("Please read the following messages.", 0, 
        "Please read the following messages.".Length, 16)

(Это не то, что другие ответы не дают, и только от отражателя)
Если емкость меньше длины строки, которая в данном случае равна:

while (capacity < length)
{
    capacity *= 2;
    if (capacity < 0)
    {
        capacity = length;
        break;
    }
}

В Mono конструктор StringBuilder(string val) выделяет емкость для int.MaxValue, пока не произойдет добавление.

Реальный ответ заключается в том, что метод вызывается внутренне в CLR, где длина - это емкость:

[MethodImpl(MethodImplOptions.InternalCall)]
private static extern string FastAllocateString(int length);

Я не могу найти источник для этого в SSCLI , однако версия Mono (\ mono \ metadata \ object.c) делает это так:

mono_string_new_size (MonoDomain *domain, gint32 len)
{
    MonoString *s;
    MonoVTable *vtable;
    size_t size = (sizeof (MonoString) + ((len + 1) * 2));

...
}

Какой размер в байтах объекта MonoString плюс длина, умноженная на 2.

...