2012-01-11 18 views
7

Estoy trabajando en un código de alto rendimiento en el que esta construcción es parte de la sección de rendimiento crítico.Creación de cadenas inseguras a partir de char []

Esto es lo que sucede en alguna sección:

  1. Un string es escaneado y metadatos se almacena de manera eficiente.
  2. Según estos metadatos, los trozos de la cadena principal están separados en char[][].
  3. Eso char[][] se debe transferir a string[].

Ahora, sé que sólo puede llamar new string(char[]) pero entonces el resultado tendría que ser copiado.

Para evitar que ocurra este paso de copia adicional, supongo que debe ser posible escribir directamente en el búfer interno de la cadena. Aunque esto sería una operación insegura (y sé que esto trae muchas implicaciones, como desbordamiento, compatibilidad con versiones anteriores).

He visto varias formas de lograr esto, pero no estoy realmente satisfecho con ninguna.

¿Alguien tiene sugerencias verdaderas sobre cómo lograr esto?

información adicional:
El proceso actual no incluye la conversión a char[] necesariamente, es prácticamente una operación de 'multi-subcadena'. Como 3 índices y sus longitudes anexadas.

El StringBuilder tiene demasiada sobrecarga para la pequeña cantidad de concats.

EDIT:
Debido a algunos aspectos imprecisos de lo que es exactamente eso lo que te pido, le formularé de ella.

Esto es lo que sucede:

  1. cadena principal está indexado.
  2. Las partes de la cadena principal se copian a char[].
  3. El char[] se convierte en string.

Lo que me gustaría hacer es fusionar el paso 2 y 3, lo que resulta en:

  1. cadena principal está indexado.
  2. Las partes de la cadena principal se copian a string (y el GC puede mantener sus manos alejadas durante el proceso mediante el uso adecuado de la palabra clave fixed?).

Y una nota es que no puede cambio el tipo de salida de string [], ya que esta es una biblioteca externa, y los proyectos dependen de él (compatibilidad con versiones anteriores).

+2

¿Qué tienes que hacer con las cuerdas después de todo esto? Es decir, en lugar de tratar de encontrar formas de mapear a 'string []' sin copiar de nuevo, ¿puede traerlo como un 'char []' y luego almacenar los pares 'int, int' de la posición y longitud del las subpartes que necesita, haciendo referencia a la matriz original para extraer las subcadenas cuando las necesite? –

+0

No estoy seguro del código que intentas mejorar aquí. –

+2

La clase de cadena es especial; es por definición inmutable e implica copiar. Tratar de eludir esto es pedir problemas con el GC y otro código administrado (las cadenas se agrupan). – Nikki9696

Respuesta

2

¿Qué ocurre si lo hace:

string s = GetBuffer(); 
fixed (char* pch = s) { 
    pch[0] = 'R'; 
    pch[1] = 'e'; 
    pch[2] = 's'; 
    pch[3] = 'u'; 
    pch[4] = 'l'; 
    pch[5] = 't'; 
} 

creo que el mundo llegará a su fin (o al menos la parte de .NET logró), pero eso es muy cercano a lo StringBuilder hace.

¿Tiene los datos del perfilador para mostrar que StringBuilder no es lo suficientemente rápido para sus propósitos, o es una suposición?

+0

Asunción, porque muchas veces ni siquiera habrá concatos, y la mayoría cuando hay, solo habrá 2-4 concats. No estamos hablando de números enormes. Déjame probar la muestra de código que has proporcionado :). – Aidiakapi

+0

Lo he perfilado ahora, lo que resulta en (menos es mejor) 2720 para este método, 4291 con 'char []' y 'nueva cadena (theArray)', y finalmente 5165 para 'StringBuilder'. – Aidiakapi

+0

¿Sabes si esto tiene efectos secundarios? – Aidiakapi

2

Creo que lo que está pidiendo hacer es 'dividir' una cadena existente en el lugar en múltiples cadenas más pequeñas sin reasignar matrices de caracteres para las cadenas más pequeñas. Esto no funcionará en el mundo administrado.

Por una razón, considere lo que sucede cuando el recolector de basura viene y recoge o mueve la cadena original durante un compaction - todas esas otras cadenas 'dentro' apuntan a otra memoria arbitraria, no al Cuerda original de la que los talló.

EDITAR: A diferencia de la respuesta de Ben (que es inteligente, pero en mi humilde opinión un poco aterradora), puede asignar un StringBuilder con una capacidad predefinida, lo que elimina la necesidad de reasignar el interno matrices. Ver http://msdn.microsoft.com/en-us/library/h1h0a5sy.aspx.

+0

Sé que la respuesta es tarde. Pero no estoy intentando mapear las subcadenas como parte de la cadena principal, sí quiero copiarlas, pero no copiarlas a 'char []' y luego a 'cadena', quiero mapearlas directamente a una 'cadena'. – Aidiakapi

+0

No hay forma de que sepa hacer eso en el CLR. Todos los constructores de cadenas, incluso los inseguros que toman un puntero a una matriz de cadenas (http://msdn.microsoft.com/en-us/library/6y4za026.aspx), funcionan al copiar la matriz. –

+0

Ben Voigt ya se suministró de una manera que parece hacer eso hasta ahora. – Aidiakapi

2

Simplemente cree su propio sistema de direccionamiento en lugar de tratar de usar un código inseguro para asignarlo a una estructura interna de datos.

mapear una string (que también se puede leer como un char[]) a una matriz de cadenas más pequeñas no es diferente de la construcción de una lista de información de dirección (índice & longitud de cada subcadena). Por lo tanto, cree un nuevo List<Tuple<int,int>> en lugar de un string[] y use esos datos para devolver la cadena correcta de su estructura de datos original sin modificaciones. Esto podría encapsularse fácilmente en algo que expuso string[].

+0

Lamento no dejar en claro que el tipo de devolución no se pudo cambiar, debido a las dependencias. – Aidiakapi

+0

¿Quiere decir que esta función debe aceptar absolutamente solo una 'cadena' y devolver solo una instancia real de 'cadena []' (por ejemplo, no puede devolver 'IList ')? Si es para una biblioteca, creo que preferiría un tipo de devolución más general. –

+0

'Array' es más específico que' IList 'y si los consumidores desean utilizarlo como' IList ', entonces son libres de hacerlo, pero no puedo suponer que lo hagan, por ejemplo, si un consumidor lo usó en Array.Copy su código se rompería. (Y tendrían que refactorizar Length to Count, etc.) – Aidiakapi

0

En .NET, no hay forma de crear una instancia de String que comparta datos con otra cadena. Alguna discusión sobre por qué aparece aparece en this comment de Eric Lippert.

+0

Él dice que no es imposible, además de que no estoy tratando de compartir datos, intento copiar una vez. – Aidiakapi

+0

¿Tan solo está buscando 'String.Substring()'? –

+0

No>. <, Como '" cadena1 ".Substring (x1, y1) +" cadena2 ".Substring (x2, y2) +" cadena3 ".Substring (x3, y3)' – Aidiakapi

Cuestiones relacionadas