Pregunta cadena c_str () vs. datos ()


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

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


74
2017-10-11 20:59


origen


Respuestas:


La documentación es correcta Utilizar c_str() si quieres una cadena terminada nula

Si los implementadores sucedieron para implementar data() en términos de c_str() no tienes que preocuparte, sigue usando data() si no necesita que la cadena sea terminada nula, 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 data() es más significativo. 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 sea terminado en nulo. De acuerdo a cppreference: "La matriz devuelta tiene terminación nula, es decir, data () y c_str () realizan la misma función".


83
2017-10-11 21:01



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

21.4.7.1 basic_string accesors [string.accessors]

const charT* c_str() const noexcept; 

const charT* data() const noexcept; 

1 Devoluciones: 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 devoluciones: *(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á.


21
2017-09-13 04:41



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 compiladores. También es posible que su compilador 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 programa:

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.


17
2017-10-11 21:12



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

std::string operaciones, p. iteración, concatenación y mutación de elemento - no necesita el cero terminador. A menos que pase el string a una función que espera 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 los datos de cadena compartidos, y el rango de inicio / finalización, evitando la copia (y la asignación adicional) de los datos de cadena reales. 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).


Similar, string::data permite una representación interna diferente, p. 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 c_str o data.


2
2017-07-01 08:04



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.

1
2017-10-05 13:04