2012-01-12 30 views
26

Mi código convierte cadenas de C++ a CStrings con cierta frecuencia, y me pregunto si la cadena original está asignada en la pila, ¿se asignará también la CString en la pila? Por ejemplo:string.c_str() ¿es necesario desasignar?

string s = "Hello world"; 
char* s2 = s.c_str(); 

Se s2 ser asignados en la pila, o en el montón? En otras palabras, ¿tendré que eliminar s2?

Por el contrario, si tengo este código:

string s = new string("Hello, mr. heap..."); 
char* s2 = s.c_str(); 

Will s2 estar ahora en el montón, ya que su origen estaba en el montón?

Para aclarar, cuando pregunto si s2 está en el montón, sé que el puntero está en la pila. Estoy preguntando si lo que apunta a estará en el montón o en la pila.

Respuesta

32
string s = "Hello world"; 
char* s2 = s.c_str(); 

s2 se asignarán en la pila, o en el montón? En otras palabras ... ¿Tendré que eliminar s2?

s2 está en la pila, sí. Pero, es un puntero a un personaje (que en este caso pasa a ser el primer personaje en una representación ASCIIZ del contenido de texto de s). Ese texto en sí es donde el objeto s sintió ganas de construir esa representación.Las implementaciones pueden hacer eso como quieran, pero la opción de implementación crucial para std::string es si proporcionan una "optimización de cadena corta" que permite insertar cadenas muy cortas directamente en el objeto s y si "Hello world" es lo suficientemente corto beneficiarse de esa optimización:

  • si es así, entonces s2 apuntaría a apilar memoria asignada dentro s
  • de otro modo, en el interior s habría un puntero a la memoria/montón asignado-tienda libre en la que el "Hola mundo \ 0 "contenido cuya dirección es devuelta por .c_str() aparecería, y s2 sería una copia de ese valor.

Tenga en cuenta que es c_str()const, por lo que para su código para compilar es necesario cambiar a const char* s2 = ....

No es necesario que elimine s2, no. Los datos a los que los puntos s2 aún son propiedad y están gestionados por el objeto s, serán invalidados por cualquier llamada a métodos que no sean const de s o por s que salgan del alcance.

string s = new string("Hello, mr. heap..."); 
char* s2 = s.c_str(); 

Se s2 estar ahora en el montón, ya que su origen estaba en el montón?

Este código no compila, como s no es un puntero y una cadena no tiene un constructor como string(std::string*). Se podría cambiarlo a cualquiera:

string* s = new string("Hello, mr. heap..."); 

... o ...

string s = *new string("Hello, mr. heap..."); 

Este último crea una pérdida de memoria y no sirve a ningún propósito útil, así que vamos a suponer que la primera. Entonces:

char* s2 = s.c_str(); 

... tiene que convertirse ...

char* s2 = s->c_str(); 

Will s2 estar ahora en el montón, ya que su origen estaba en el montón?

Sí. En todos los escenarios, especialmente si s sí mismo es en el montón, entonces:

  • incluso si hay un corto búfer de optimización cadena dentro s a la que c_str() produce un puntero, que debe ser en el montón, de lo contrario
  • si s usa un puntero a otra memoria para almacenar el texto, esa memoria también se asignará desde el montón.

Pero, de nuevo, aún sabiendo con certeza que s2 apunta a la pila de memoria asignada, su código no tiene que desasignar que la memoria - que se hará automáticamente cuando se elimina s:

string* s = new string("Hello, mr. heap..."); 
const char* s2 = s->c_str(); 
...use s2 for something... 
delete s; // "destruct" s and deallocate the heap used for it... 

De Por supuesto, generalmente es mejor usar string s("xyz"); a menos que necesite una vida más allá del alcance local, y std::unique_ptr<std::string> o std::shared_ptr<std::string> de lo contrario.

12

c_str() devuelve un puntero a un búfer interno en el objeto string - nunca lo ha hecho free()/delete.

Solo es válido siempre que el alcance sea el string. Además, si llama a un método no const del objeto string, ya no se garantiza su validez.

http://www.cplusplus.com/reference/string/string/c_str/

(Editado por claridad sobre la base de comentarios a continuación)

+0

¿Interesante, entonces, nunca liberarías el char * porque al hacerlo liberarías datos internos en la cadena? c_str() contiene literalmente la misma dirección que los datos reales que está usando la cadena? ¿Múltiples llamadas a .c_str() devolverían la misma dirección de esa manera? (Solo aclaro para que sepa que entiendo) –

+0

@Georges la respuesta a algunas de esas preguntas depende de si está usando el último estándar o el anterior. Es posible que desee aclarar cuál le interesa. –

+0

@ R.MartinhoFernandes Mejor ir con el último estándar. Sin embargo, sería interesante saber qué tan reciente es esta norma –

0

Eso depende. Si recuerdo correctamente, CString hace una copia de la cadena de entrada, por lo que no, no necesitaría tener ninguna rutina especial de asignación de pila.

4

std::string::c_str() devuelve un const char*, no un char *. Esa es una buena indicación de que no es necesario liberarlo. La memoria es administrada por la instancia (consulte algunos detalles en this link, por ejemplo), por lo que solo es válida mientras la instancia de cadena es válida.

+6

La const-calificación de la punta-a objeto no es en absoluto una indicación de que doesn no necesita ser liberado por la persona que llama. –

+0

@JamesMcNellis: true para objetos. Pero un 'char *' no es exactamente un objeto, solo un tipo simple de C. Y en C llano la constness se usa generalmente para indicar que "usted no posee esta memoria" (ya que 'free (3)' toma un puntero no const). – vanza

+0

@JamesMcNellis: ¿qué ejemplos de tales funciones hay? Lo consideraría muy confuso y comentaría muy claramente cuando el llamante debía liberar el objeto apuntado de un puntero 'const' devuelto. – leftaroundabout

2

s2 serán válidos siempre que s permanezca en el alcance. Es un puntero a la memoria que posee s. Ver p. this MSDN documentation: "la cadena tiene una vida útil limitada y pertenece a la cadena de clases".

Si desea utilizar std::string dentro de una función como fábrica para la manipulación de cadenas, y luego devolver cadenas tipo c, debe asignar almacenamiento de almacenamiento dinámico para el valor de retorno. Obtenga espacio usando malloc o new, y luego copie el contenido de s.c_str().

1

¿Se asignará s2 en la pila o en el montón?

Podría estar en cualquiera de los dos. Por ejemplo, si la clase std::string realiza una optimización de cadena pequeña, los datos residirán en la pila si su tamaño está por debajo del umbral de SSO, y en el montón de lo contrario. (Y todo esto está asumiendo que el objeto std::string está en la pila.)

¿Debo eliminar s2?

No, el objeto de matriz de caracteres devuelto por c_str es propiedad del objeto de cadena.

¿S2 ahora estará en el montón, ya que su origen estaba en el montón?

En este caso, los datos probablemente residirán en el montón de todos modos, incluso cuando se hace SSO. Pero rara vez hay una razón para asignar dinámicamente un objeto std::string.

+0

Gracias por la respuesta muy detallada :) –

4

En primer lugar, incluso su cadena original no está asignada en la pila, como parece creer. Al menos no del todo. Si su string s se declara como una variable local, solo el objeto string se "asigna en la pila". La secuencia controlada de ese objeto de cadena se asigna en otro lugar. Se supone que no debes saber dónde está asignado, pero en la mayoría de los casos se asigna en el montón. Es decir. la cadena real "Hello world" almacenada por s en su primer ejemplo generalmente se asigna en el montón, independientemente de dónde declare su s.

En segundo lugar, aproximadamente c_str().

En la especificación original de C++ (C++ 98) c_str generalmente devuelve un puntero a un búfer independiente asignado en algún lugar. De nuevo, se supone que no debes saber dónde está asignado, pero en general se suponía que debía asignarse en el montón. La mayoría de las implementaciones de std::string se aseguraron de que su secuencia controlada fuera siempre terminada en cero, por lo que su c_str devolvió un puntero directo a la secuencia controlada.

En la nueva especificación de C++ (C++ 11) ahora se requiere que c_str devuelva un puntero directo a la secuencia controlada.

En otras palabras, en el caso general, el resultado de c_str apuntará a una memoria asignada en el montón incluso para objetos locales std::string. Su primer ejemplo no es diferente de su segundo ejemplo al respecto. Sin embargo, en cualquier caso, la memoria apuntada por c_str() no es de su propiedad. No se supone que debes desasignarlo. Se supone que ni siquiera debes saber dónde está asignado.

Cuestiones relacionadas