2010-02-15 7 views
6

Me pregunto si este código ...¿Un StringBuilder inicializado con una cadena contiene exactamente (solo) espacio suficiente para esa cadena?

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

... inicializa sb con un tampón exactamente tan grande como la cadena que se pasa al constructor. Por un lado, esto parecería lo más lógico. Por otro lado, parece una especie de fracaso el objetivo de la clase StringBuilder para uno de sus usos más comunes, que es proporcionar mutabilidad para hacer que los anexos repetidos sean más eficientes. (La primera llamada a Append, si la respuesta a mi pregunta es "sí", requeriría sb para cambiar el tamaño en sí.)

Por otra parte, supongo que se podría ver esto como análogo al constructor para List<T> que toma una IEnumerable<T> como parámetro. Tal vez la suposición en este caso es que no está planeando agregar a, sino más bien en manipulando lo que ya está allí.

La única verdadera investigación que he hecho en esta era comprobar la MSDN documentation on StringBuilder, que no proporcionó una respuesta (se dice que el constructor inicializa la instancia "por medio de la cadena especificada," pero no indica cómo la cuerda se usa).


EDITAR: Por lo que es, no parece extraño para nadie más "aplicación específica" ... esto? Quiero decir, el propósito de la clase StringBuilder es ofrecer una alternativa para realizar muchas operaciones en un string, creando una tonelada de instancias inmutables string en el camino; por lo tanto, es para eficiencia. Siento que se debe especificar el comportamiento de este constructor, de modo que el desarrollador pueda tomar una decisión informada sobre cómo usarlo independientemente de la plataforma.

Es decir, es implementado por Microsoft de cierta manera; podrían haberlo puesto fácilmente en la documentación (obligando a otras implementaciones a seguir su ejemplo). Solo una fuente personal de perplejidad ...

Respuesta

5

Es un detalle de implementación del que no debería preocuparse.Sin embargo, usando .NET reflector, y buscando en la sobrecarga (cadena, int32, int32, int32) del constructor (que los otros constructores llaman), podemos ver que elige una capacidad que es un múltiplo de 16 (el siguiente más grande sobre el solicitado tamaño)

Edición

en realidad, es de 16 x 2^n, con el valor de "n" seleccionado para ser el siguiente tamaño más grande

+0

Buena decisión - I j Ust comprobé esto yo mismo y llegué a la misma conclusión (al verificar la propiedad 'Capacidad' después de la inicialización ... de alguna manera esto no se me ocurrió hasta después de haber publicado la pregunta). –

+1

... y aún así no deberías confiar en esto. Si le importa lo suficiente acerca de la capacidad requerida para publicar una pregunta sobre el desbordamiento de pila, debe usar una de las sobrecargas donde puede especificarla. El propósito completo de "implementación específica" significa que puede cambiar en el futuro. No confíes en el comportamiento indocumentado. –

+0

@Lasse - Oh, de acuerdo. No recomendaría * confiar * en este detalle. (Y luchando por pensar cómo podrías confiar en este hecho) –

4

Compruebe el miembro de capacidad de StringBuilder.

De MSDN:

El StringBuilder asigna dinámicamente más espacio cuando sea necesario y aumenta la capacidad en consecuencia. Por razones de rendimiento, un StringBuilder podría asignar más memoria de la necesaria. La cantidad de memoria asignada es específica de la implementación.

2

el constructor se ha vinculado a es probablemente encadenado a la StringBuilder(String, Int32, Int32, Int32):

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

Por lo tanto, para la cadena, probablemente pasaría por: cadena, 0, cadena.Largo, cadena.Length. O algo similar que tenga sentido en el contexto de StringBuilder.

+0

Suena como (de la respuesta de Damien, para la que usó Reflector) tu primer "probablemente" era correcto, y tu segundo estaba cerca (en realidad el siguiente poder de 16, en lugar de solo 'string.Length'). –

+0

... y por "la próxima potencia de 16", quiero decir "16 veces la próxima potencia de 2". No creo que después de 16 vaya directamente a 256 y luego a 4096 (soy estúpido). –

1

El constructor que finalmente es llamada es:

// "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) 

(Esto no es nada que las otras respuestas no proporcionan, y es sólo de reflector)
Si la capacidad es menor que la longitud de la cadena, que es en este caso:

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

en mono, la StringBuilder(string val) constructor asigna la capacidad de int.MaxValue hasta que se produce un append.

La verdadera respuesta radica en el método que acaba de ser llamado internamente en el CLR, donde la longitud es la capacidad de:

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

no puedo encontrar la fuente para esto en el SSCLI sin embargo la versión Mono (\ mono \ metadatos \ object.c) hace como este:

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

... 
} 

¿Cuál es el tamaño en bytes de un objeto MonoString, más la longitud veces 2.

+0

¿De dónde viene esta información? ¿Estás usando Windows, Mono o ...? Parece que tus hallazgos con respecto a la capacidad inicial de 'StringBuilder' difieren de los de Damien (y los míos). –

+0

@Dan - un pequeño error con 0x10 :) –

+0

El código que ha proporcionado es útil, pero entra en conflicto con lo que ha dicho. "El constructor utiliza la longitud de su cadena como la capacidad" - esto no es cierto; ese bucle 'while' duplica' capacidad' hasta 'capacidad> = longitud'; por lo tanto, va a ser su valor inicial (que parece ser 16) multiplicado por 2. –

Cuestiones relacionadas