2010-12-29 20 views
13

¿Cuál es la diferencia fundamental, si existe, entre un C++ std :: vector y std :: basic_string?Vector frente a cadena

+1

Compruebe los documentos, tienen diferentes interfaces. Si especificó el problema real que está resolviendo, las respuestas también podrían haber sido más específicas. –

+1

@Gene: Tienen diferentes interfaces, pero ambas implementan todo lo necesario para ser un contenedor de secuencia STL. –

+0

@Gene: No estoy resolviendo ningún problema en particular, solo tengo curiosidad sobre por qué debería elegir uno u otro para varios propósitos: no estoy contando la existencia de algunos métodos adicionales de cadenas como fundamentales. Realmente no cuento el rendimiento como fundamental tampoco. Sin embargo, la validez de los iteradores es la respuesta a varias respuestas. Y tengo una vaga sospecha de que el tipo de datos para una cadena debe tener un valor de "Cero como" para poner al final del método data() (obtenido de una característica de los rasgos). – Yttrill

Respuesta

0

Un vector es una estructura de datos que simula una matriz. En el fondo es en realidad una matriz (dinámica).

La clase basic_string representa una secuencia de caracteres. Contiene todas las operaciones habituales de una secuencia y, adicionalmente, contiene operaciones de cadena estándar, como búsqueda y concatenación.

Puede usar el vector para guardar cualquier tipo de datos que desee std::vector<int> or <float> or even std::vector< std::vector<T> > pero basic_string solo se puede usar para representar "texto".

+0

Estoy seguro de que podría encontrar una manera de hacer que una 'basic_string' esté llena de dobles o algo igualmente malvado y que realmente" funcione ". –

+0

Bueno, la mayoría de las implementaciones implementan 'basic_string' en términos de algo así como' vector'. Y cualquier tipo para el que se define una clase 'char_traits' funcionará con' std :: basic_string', incluso si usted hizo un 'char_traits ' (como está escrito en el comentario de @Noah) –

+0

@Billy - no es verdadero. Algunas de las mismas técnicas pueden usarse en ambos, pero NUNCA he visto una 'basic_string' implementada en términos de' vector'. De hecho, una implementación muy común, que se distribuye con MSVC++, es MUY diferente ya que utilizan la optimización de cadenas pequeñas (cualquier elemento lo suficientemente pequeño como para caber en un puntero queda atascado en el puntero al almacenamiento intermedio en lugar de asignar uno). –

0

basic_string proporciona muchas opciones de comparación específicas de cadenas. Tiene razón en que la interfaz de administración de memoria subyacente es muy similar, pero la cadena contiene muchos miembros adicionales, como c_str(), que no tendría sentido para un vector.

+0

No creo que exista un vector que use la optimización de cadenas pequeñas. No he salido a buscar uno, pero estoy bastante seguro de que no está allí. No sería tan útil. La verdad es que las dos cosas son simplemente diferentes. Tienen diferentes propósitos y, por lo tanto, a menudo se implementan MUY diferente, aunque un enfoque ingenuo puede ser similar en ambos. –

+0

@Noah: De ahí por qué dije "interfaz". – Puppy

+0

¿Qué comparaciones son específicas de una cadena? Dado que el tipo de datos del elemento es variable en ambos casos, las cosas como la comparación lexicográfica tienen tanto sentido para los vectores como las cadenas. Por supuesto, una comparación insensible a mayúsculas/minúsculas sería específica de una cadena, pero luego la cadena no sería polimórfica. – Yttrill

5

La diferencia clave es que std::vector debe mantener sus datos en la memoria continua, cuando std::basic_string no pudo. Como resultado:

std::vector<char> v('a', 3); 
char* x = &v[0]; // valid 

std::basic_string<char> s("aaa"); 
char* x2 = &s[0];  // doesn't point to continuous buffer 
//For example, the behavior of 
std::cout << *(x2+1); 
//is undefined. 
const char* x3 = s.c_str(); // valid 

On practice this difference is not so important.

+0

Err .. ese ejemplo de código es perfectamente válido.Ahora bien, si modificó 'x2' utilizando la aritmética del puntero, es posible que no sea válido (dependiendo de su compilador), pero no conozco ningún compilador que lo haga. –

+0

No conozco ese compilador también, pero no debes contar con esos puntos 'x2' para el buffer continuo, porque C++ Standard no da ninguna garantía. –

+2

Ninguno de ellos es válido en realidad. Ninguno de los objetos tiene ningún tamaño y, por lo tanto, el primer elemento es uno pasado y no se puede desreferenciar ese elemento. Solo el c_str() está bien definido. –

11

basic_string da compilador y las implementaciones de la biblioteca estándar, unas pocas libertades más vectorial:

  1. La "optimización de la cadena pequeña" es válida en las cuerdas, lo que permite implementaciones para almacenar la cadena real, en lugar de un puntero a la cadena, en el objeto cadena cuando la cadena es corta. Algo a lo largo de las líneas de:

    class string 
    { 
        size_t length; 
        union 
        { 
         char * usedWhenStringIsLong; 
         char usedWhenStringIsShort[sizeof(char*)]; 
        }; 
    }; 
    
  2. En C++ 03, la matriz subyacente no tiene por qué ser contiguos. Implementar basic_string en términos de algo así como una "cuerda" sería posible bajo el estándar actual. (Aunque nadie hace esto porque eso haría que los miembros std::basic_string::c_str() y std::basic_string::data() fueran demasiado caros de implementar).
    C++ 11 ahora prohíbe este comportamiento.

  3. En C++ 03, basic_string permite al proveedor del compilador/biblioteca para utilizar la copia en escritura para los datos (que puede ahorrar en las copias), que no está permitido para std::vector. En la práctica, esto solía ser mucho más común, pero hoy es menos común debido al impacto que tiene en el multihilo. De cualquier manera, su código no puede depender de si se implementa o no std::basic_string utilizando COW.
    C++ 11 nuevamente prohíbe este comportamiento.

Hay algunos métodos de ayuda viraron a basic_string así, pero la mayoría son simples y, por supuesto, podría ser fácilmente implementado en la parte superior de vector.

+0

No me gusta pensar en (1) como una razón para elegir o usar std :: string es un efecto secundario involuntario de la redacción estándar que se ha ajustado en el nuevo estándar. (2) fue una buena razón para usar std :: string ya que hizo que devolver cadenas de métodos muy eficientes (prácticamente sin costo) lamentablemente se está eliminando debido a los requisitos de paralelismo (aunque al leer el documento que recomienda esto, parece que la cuerda ocupará ese manto de COW con el tiempo (tendremos que esperar y ver si esto funciona). –

+0

@Martin: Esto es cierto. La semántica del movimiento OTOH elimina a MUCHOS de los casos en que las implementaciones COW aceleraron las cosas :) –

15
  • basic_string no llama a constructores y destructores de sus elementos. vector hace.

  • swapping basic_string invalida iteradores (permitiendo la optimización de cadenas pequeñas), intercambiando vectores no.

  • basic_string la memoria no se puede asignar continuamente en C++ 03. el vector es siempre continuo. Esta diferencia se elimina en C++ 0x [string.require]:

    Los objetos de char-como en un objeto basic_string serán almacenados de forma contigua

  • basic_string tiene interfaz para operaciones de cadenas. el vector no.

  • basic_string puede usar copiar en la estrategia de escritura (en pre C++ 11). el vector no puede

citas relevantes para los no creyentes:

[basic.string]:

El basic_string plantilla de clase se ajusta a los requisitos de un contenedor de secuencias (23.2.3), para una Contenedor reversible (23.2), y para un contenedor compatible con Allocator (Tabla 99), excepto que basic_string no construye ni destruye sus elementos utilizando allocator_traits :: construc y allocator_- rasgos :: destroy y ese swap() para basic_string invalida iteradores. Los iteradores compatibles con por basic_string son iteradores de acceso aleatorio (24.2.7).

+0

@Billy: lea el estándar antes de downvoting, he agregado la cita. – ybungalobill

+0

Por lo que puedo decir, esa cita no es de 'la norma' sino del borrador de C++ 0x. Está bien y vale la pena mencionarlo, pero debe calificarlo con "En C++ 0x ...". – GManNickG

+0

@GMan: Hmm, parece que tienes razón. Pero solo la formulación es diferente, C++ 98 todavía dice que solo asigna y desasigna los elementos. Este cambio es solo una aclaración. – ybungalobill

0

Una diferencia entre std::string y std::vector es que los programas pueden construir una cadena de una cadena terminada en nulo, mientras que con los vectores que no pueden.

std::string a = "hello";   // okay 
std::vector<char> b = "goodbye"; // compiler error 

Esto a menudo hace que las cadenas sean más fáciles de trabajar.

0

TLDR: string s están optimizados para contener sólo las primitivas de caracteres, vector s pueden contener primitivas o objetos

La diferencia preeminente entre vector y string es que vector pueden contener correctamente objetos, string sólo funciona en primitivas. Así vector proporciona estos métodos que serían inútiles para un string trabajar con elementos:

  1. vector::emplace
  2. vector::emplace_back
  3. vector::~vector

Incluso se extiende string no permitirá que le permite manejar correctamente los objetos, porque carece de un destructor.Esto no debe ser visto como una desventaja, que permite la optimización significativa sobre vector en que string puede:

  1. Haz short string optimization, evitando potencialmente asignación del montón, con little-no increased storage overhead
  2. Uso char_traits, uno de plantilla string 's argumentos, para definir cómo las operaciones se deben implementar en las primitivas de contenidos (de los cuales sólo char, wchar_t, char16_t, y char32_t se implementan: http://en.cppreference.com/w/cpp/string/char_traits)

Particularmente relevantes son char_traits::copy, char_traits::move y char_traits::assign, lo que obviamente implica que se utilizará la asignación directa, en lugar de la construcción o destrucción, que es nuevamente preferible para los primitivos. Toda esta especialización tiene los inconvenientes adicionales a string que:

  1. Sólo char, se utilizará wchar_t, char16_t o char32_t tipos primitivos. Obviamente, las primitivas de tamaños de hasta 32 bits, podrían utilizar su tamaño equivalente char_type: https://stackoverflow.com/a/35555016/2642059, pero para las primitivas tales como long long tendría que ser escrito una nueva especialización de char_traits, y la idea de especializarse char_traits::eof y char_traits::not_eof en lugar de sólo usar vector<long long> no parece ser el mejor uso del tiempo.
  2. Debido a la optimización de cadena corta, iteradores son invalidadas por todas las operaciones que pudieran invalidar un iterador vector, pero string iteradores son, además, invalidado por string::swap y string::operator=

diferencias adicionales en las interfaces de vector y string:

  1. no hay mutable string::data: Why Doesn't std::string.data() provide a mutable char*?
  2. string proporciona funcionalidad para trabajar con palabras no disponibles en vector: string::c_str, string::length, string::append, string::operator+=, string::compare, string::replace, string::substr, string::copy, string::find, string::rfind, string::find_first_of, string::find_first_not_of, string::flind_last_of, string::find_last_not_of, string::operator+, string::operator>>, string::operator<<, string::stoi, string::stol, string::stoll, string::stoul, string::stoull, string::stof, string::stod, string::stold, stirng::to_string, string::to_wstring
  3. Finalmente todas partes vector acepta los argumentos de otra vector, string acepta un string o un char*

Nota esta respuesta está escrito en C++ 11 en contra, por lo que se requieren string s que se asignarán de forma contigua.

Cuestiones relacionadas