cadena c_str () vs. datos ()

He leído varios lugares en los que la diferencia entre c_str() y data() (en STL y otras implementaciones) es que c_str() siempre termina nulo mientras que data() no. Por lo que he visto en implementaciones reales, hacen lo mismo o data() llamadas a data() c_str() .

¿Que me estoy perdiendo aqui? ¿Cuál es más correcto usar en qué escenarios?

La documentación es correcta Use c_str() si quiere una cadena terminada nula.

Si los implementadores sucedieron para implementar data() en términos de c_str() no tiene que preocuparse, aún use data() si no necesita que la cadena sea terminada en nulo, en alguna implementación puede funcionar mejor que c_str ().

Las cadenas no tienen necesariamente que estar compuestas de datos de caracteres, sino que se pueden componer con elementos de cualquier tipo. En esos casos, los data() son más significativos. c_str() en mi opinión solo es realmente útil cuando los elementos de tu cadena están basados ​​en caracteres.

Extra : en C ++ 11 en adelante, se requiere que ambas funciones sean las mismas. es decir data ahora se requiere que los datos sean terminados en nulo. De acuerdo con cppreference : “La matriz devuelta tiene terminación nula, es decir, data () y c_str () realizan la misma función”.

En C ++ 11 / C ++ 0x , data() y c_str() ya no son diferentes. Y, por lo tanto data() se requiere que data() tenga una terminación nula al final.

21.4.7.1 basic_string cadena basic_string [string.accessors]

const charT* c_str() const noexcept;

const charT* data() const noexcept;

1 Devuelve: Un puntero p tal que p + i == &operator[](i) para cada i en [0,size()] .


21.4.5 acceso al elemento basic_string [string.access]

const_reference operator[](size_type pos) const noexcept;

1 Requiere: pos < = tamaño (). 2 Devuelve: *(begin() + pos) if pos < size() ; de lo contrario, una referencia a un objeto de tipo T con valor charT(); el valor referenciado no se modificará.

Incluso si sabe que ha visto que hacen lo mismo, o que .data () llama a .c_str (), no es correcto suponer que este será el caso para otros comstackdores. También es posible que su comstackdor cambie con una versión futura.

2 razones para usar std :: string:

std :: string se puede usar para texto y datos binarios arbitrarios.

 //Example 1 //Plain text: std::string s1; s1 = "abc"; //Example 2 //Arbitrary binary data: std::string s2; s2.append("a\0b\0b\0", 6); 

Deberías usar el método .c_str () cuando estás usando tu cadena como ejemplo 1.

Debe usar el método .data () cuando esté utilizando su cadena como ejemplo 2. No porque sea peligroso utilizar .c_str () en estos casos, sino porque es más explícito que está trabajando con datos binarios para que otros revisen tu codigo.

Posible error con el uso de .data ()

El siguiente código es incorrecto y podría causar una segfault en su progtwig:

 std::string s; s = "abc"; char sz[512]; strcpy(sz, s.data());//This could crash depending on the implementation of .data() 

¿Por qué es común que los implementadores hagan que .data () y .c_str () hagan lo mismo?

Porque es más eficiente hacerlo. La única forma de hacer que .data () devuelva algo que no sea terminado en nulo, sería tener .c_str () o .data () copiar su búfer interno, o simplemente usar 2 búferes. Tener un único búfer terminado nulo siempre significa que siempre se puede usar solo un búfer interno cuando se implementa std :: string.

Ya se ha respondido, algunas notas sobre el propósito: Libertad de implementación.

std::string operations – por ejemplo, iteración, concatenación y mutación de elementos – no necesita el cero terminador. A menos que pase la string a una función esperando una cadena terminada en cero, se puede omitir.

Esto permitiría que una implementación tenga subcadenas que compartan los datos reales de la cadena: string::substr podría contener internamente una referencia a datos de cadena compartidos, y el rango de inicio / finalización, evitando la copia (y asignación adicional) de los datos de la cadena real. La implementación diferiría la copia hasta que llame a c_str o modifique cualquiera de las cadenas. No se realizaría ninguna copia si las leyes involucradas solo se leen.

(La implementación de copia sobre escritura no es muy divertida en entornos multiproceso, además de que los ahorros típicos de memoria / asignación no valen el código más complejo hoy en día, por lo que rara vez se realiza).


Del mismo modo, string::data permite una representación interna diferente, por ejemplo, una cuerda (lista vinculada de segmentos de cuerda). Esto puede mejorar significativamente las operaciones de inserción / reemplazo. de nuevo, la lista de segmentos debería colapsarse en un solo segmento cuando llame a c_str o data .

Cita de ANSI ISO IEC 14882 2003 (Estándar C ++ 03):

  21.3.6 basic_string string operations [lib.string.ops] const charT* c_str() const; Returns: A pointer to the initial element of an array of length size() + 1 whose first size() elements equal the corresponding elements of the string controlled by *this and whose last element is a null character specified by charT(). Requires: The program shall not alter any of the values stored in the array. Nor shall the program treat the returned value as a valid pointer value after any subsequent call to a non-const member function of the class basic_string that designates the same object as this. const charT* data() const; Returns: If size() is nonzero, the member returns a pointer to the initial element of an array whose first size() elements equal the corresponding elements of the string controlled by *this. If size() is zero, the member returns a non-null pointer that is copyable and can have zero added to it. Requires: The program shall not alter any of the values stored in the character array. Nor shall the program treat the returned value as a valid pointer value after any subsequent call to a non- const member function of basic_string that designates the same object as this.