¿Cómo puedo seleccionar eficazmente una Biblioteca Estándar de contenedor en C++11?

Hay una imagen bien conocido (cheat sheet) que se llama C++ Contenedor de elección». Es un diagrama de flujo para elegir el mejor envase para la quería de uso.

¿Alguien sabe si ya hay una C++11 versión?

Este es el anterior:
¿Cómo puedo seleccionar eficazmente una Biblioteca Estándar de contenedor en C++11?

  • Nunca había visto esto antes. gracias!
  • Es ya una parte de la C++-Faq aquí en TAN.
  • C++11 sólo introdujo una nueva cierto tipo de contenedor: el unordered_X contenedores. Incluso ellos sólo machaca la tabla considerablemente, ya que hay una serie de consideraciones a la hora de decidir si un hash de la tabla es la adecuada.
  • También forward_list y array. Y la desordenada de los contenedores no realmente salir del paso, se acaba de agregar un nuevo clúster enlazadas desde «la Necesidad de encontrar el elemento clave».
  • La desordenada de contenedores, sería un gran grupo; esa es la razón por la que no machaca la tabla. Decidir si se utiliza una tabla hash o no, no es un simple par de decisiones.
  • Pero eso es ya cierto para las personas mayores de contenedores. A menudo utilizo un std::vector para ordenó contenedores, manteniendo los datos ordenados de mí mismo.
  • James es el adecuado, hay más casos de uso de vectores que lo que se muestra en la tabla. La ventaja de la localidad de los datos supera en muchos casos a la falta de eficiencia en algunas operaciones (más pronto de C++11). No me parece que el correo gráfico tan útil incluso para c++03
  • Esto es lindo, pero creo que la lectura de cualquier libro de texto sobre estructuras de datos que te dejará en un estado del cual no sólo se podía reinventar este diagrama de flujo en un par de minutos, pero también sé muchas más cosas útiles que este diagrama de flujo se pasa por alto.
  • Hay alguna versión actualizada del diagrama de flujo de todos modos? Es fácil y muy buen planificador.
  • «Es importante el orden?» -> Ordenar el vector. «Almacén de claves separadas para el valor?» -> Uso vector< tupla<clave, valor>> y ordenados por clave.

InformationsquelleAutor BlakBat | 2012-05-22

4 Kommentare

  1. 93

    No, que yo sepa, sin embargo se puede hacer textualmente, supongo. También, el gráfico es un poco fuera, porque list no es un buen contenedor en general, y tampoco es forward_list. Ambas listas son muy especializada de contenedores para aplicaciones de nicho.

    Para construir un gráfico, sólo necesita dos sencillas pautas:

    • Elegir para la semántica primera
    • Cuando varias opciones están disponibles, ir a por el más simple

    Preocuparse por el rendimiento es generalmente inútil al principio. El big O consideraciones en realidad sólo se activan cuando se inicie el manejo de un par de miles (o más) de los elementos.

    Hay dos grandes categorías de contenedores:

    • Asociativa contenedores: tienen un find operación
    • Simple Secuencia de contenedores

    y, a continuación, puede crear varios adaptadores en la parte superior de ellos: stack, queue, priority_queue. Voy a dejar la adaptadores de aquí, son lo suficientemente especializados para ser reconocible.


    Pregunta 1: Asociativa ?

    • Si usted necesita para buscar fácilmente por uno clave, entonces usted necesita un contenedor asociativo
    • Si necesita disponer de elementos ordenados, entonces usted necesita una orden asociativo contenedor
    • De lo contrario, salte a la pregunta 2.

    Pregunta 1.1: Ordenó ?

    • Si usted no necesita un orden específico, utilice un unordered_ contenedor, de lo contrario usar su tradicional ordenó contraparte.

    La Pregunta 1.2: Clave Independiente ?

    • Si la clave es independiente del valor de uso de un map, de lo contrario usar set

    La Pregunta 1.3: Duplicados ?

    • Si desea conservar los duplicados, utilice un multi, de lo contrario no.

    Ejemplo:

    Supongamos que tengo varias personas con un IDENTIFICADOR único asociado a ellos, y me gustaría recuperar a una persona los datos de su IDENTIFICACIÓN tan simplemente como sea posible.

    1. Quiero un find función, por lo tanto un contenedor asociativo

      1.1. No podría cuidar menos sobre pedido, por lo que una unordered_ contenedor

      1.2. Mi key (ID) es independiente del valor al que está asociado, por lo tanto un map

      1.3. El ID es único, por lo tanto no duplicados deben aparecer.

    La respuesta final es: std::unordered_map<ID, PersonData>.


    Pregunta 2: Memoria estable ?

    • Si los elementos deben ser estables en la memoria (es decir, que no debe moverse cuando el contenedor se modifica), a continuación, utilizar algunos list
    • De lo contrario, salte a la pregunta 3.

    La Pregunta 2.1: Que ?

    • Conformarse con una list; un forward_list sólo es útil para la menor huella de memoria.

    Pregunta 3: Dinámicamente el tamaño de ?

    • Si el contenedor tiene un tamaño conocido (en tiempo de compilación), y este tamaño no va a ser modificada durante el transcurso del programa, y los elementos por defecto edificable o puede proporcionar una completa lista de inicialización (utilizando el { ... } sintaxis), a continuación, utilizar un array. Se sustituye el tradicional C-matriz, pero con funciones convenientes.
    • De lo contrario, salte a la pregunta 4.

    Pregunta 4: Doble composición ?

    • Si usted desea ser capaz de eliminar los elementos de la parte delantera y, a continuación, utilizar un deque, de lo contrario usar vector.

    Se le tenga en cuenta que, por defecto, a menos que usted necesite un contenedor asociativo, su elección va a ser un vector. Resulta que también es Sutter y Stroustrup la recomendación de.

    • +1, pero con algunas notas: 1) array no requiere de un defecto edificable tipo; 2) el retiro de la multis no es tanto acerca de los duplicados de ser permite si mantenimiento les importa (se puede poner duplicados en nomulti contenedores, lo que ocurre es que sólo uno se mantiene).
    • El ejemplo es un poco off. 1) podemos «encontrar» (no a la función de miembro, el «<algoritmo>») en un no asociativo contenedor, 1.1) si tenemos la necesidad de encontrar «eficiente», y unordered_ va a ser O(1) y O(log n).
    • es mucho más sabrosa que la std::find(map.begin(), map.end(), [&](decltype(map.front()) p) { return p.first < key; })); a pesar de que, por lo tanto, es importante que, semánticamente, que find es una función miembro en lugar de uno de <algorithm>. Como O(1) vs O(log n), no afecta a la semántica; voy a quitar el «eficiente» de el ejemplo y reemplazarlo con «facilidad».
    • «Si los elementos deben ser estables en la memoria … a continuación, utilizar algunos de la lista» … hmmm, yo pensaba que deque tenía esta propiedad también?
    • Sí y no. En un deque los elementos son estables solo si usted push/pop en los extremos; si usted empezar a insertar/borrar en el medio, a continuación, hasta N/2 elementos se barajan para llenar el vacío creado.
  2. 50

    Me gusta Matthieu la respuesta, pero voy a repetir el diagrama de flujo de como esta:

    Cuando NO usar std::vector

    De forma predeterminada, si usted necesita un contenedor de cosas, el uso de std::vector. Por lo tanto, cada contenedor sólo se justifica, a través de la funcionalidad alternativa a std::vector.

    Constructores

    std::vector requiere que su contenido se mueva-edificable, ya que se necesita para ser capaz de mezclar los elementos que lo rodean. Esto no es una carga terrible para colocar en el contenido (tenga en cuenta que los constructores predeterminados son no se requiere, gracias a emplace y así sucesivamente). Sin embargo, la mayoría de los otros contenedores no requieren ningún particular del constructor (de nuevo, gracias a emplace). Así que si usted tiene un objeto donde absolutamente no implementar un movimiento constructor, entonces usted tendrá que recoger algo más.

    Un std::deque sería el reemplazo general, teniendo muchas de las propiedades de std::vector, pero sólo se puede insertar en cualquiera de los extremos de la deque. Inserta en el medio requieran el movimiento. Un std::list lugares ningún requisito en su contenido.

    Necesidades Bools

    std::vector<bool> es… no. Bien, es estándar. Pero no es una vector en el sentido habitual, como las operaciones que std::vector normalmente permite que los están prohibidos. Y lo más ciertamente no contiene bools.

    Por lo tanto, si usted necesita real vector comportamiento de un contenedor de bools, no vas a conseguir a partir de std::vector<bool>. Así que tendrás que hacer debido a un std::deque<bool>.

    Búsqueda

    Si usted necesita para encontrar los elementos en un recipiente, y la búsqueda de la etiqueta no puede ser un índice, entonces puede que tenga que abandonar std::vector en favor de set y map. Nota la palabra clave «puede«; una ordenados std::vector a veces es una alternativa razonable. O Impulso.Del contenedor flat_set/mapa, que implementa una ordenados std::vector.

    Ahora hay cuatro variaciones de estos, cada uno con sus propias necesidades.

    • Utilizar un map cuando la búsqueda de la etiqueta no es la misma cosa como el elemento que está buscando a sí mismo. De lo contrario, utilice un set.
    • Uso unordered cuando usted tiene un mucho de los elementos en el contenedor y en el rendimiento de la búsqueda tiene que estar absolutamente O(1), en lugar de O(logn).
    • Uso multi si necesita varios elementos a tener la misma búsqueda de la etiqueta.

    De pedidos

    Si usted necesita un contenedor de cosas que siempre hay que ser ordenados en función de una determinada operación de comparación, se puede utilizar un set. O un multi_set si necesita varios elementos que tienen el mismo valor.

    O puede utilizar un criterio de std::vector, pero usted tendrá que mantener ordenados.

    Estabilidad

    Cuando los iteradores y referencias se invalidan a veces es una preocupación. Si usted necesita una lista de elementos, que tienen los iteradores/punteros a los elementos en varios otros lugares, entonces std::vector‘s enfoque a la invalidación puede no ser apropiado. Cualquier tipo de inserción de la operación puede provocar la invalidación, y dependiendo del tamaño y capacidad.

    std::list ofrece una garantía firme: un iterador y sus asociados referencias/punteros son sólo invalidado cuando el propio artículo se retira del recipiente. std::forward_list si la memoria es un motivo de grave preocupación.

    Si eso es demasiado fuerte garantía, std::deque ofrece una más débil, pero útil garantía. La invalidación de los resultados de las inserciones en el medio, pero las inserciones en la cabeza o de la cola hace que sólo invalidación de iteradores, no punteros o referencias a los elementos en el contenedor.

    Rendimiento De La Inserción

    std::vector sólo proporciona hoteles de inserción al final (e incluso entonces, se vuelve muy costoso si usted sopla de capacidad).

    std::list es costoso en términos de rendimiento (cada nuevo elemento insertado los costos de una asignación de memoria), pero es consistente. También ofrece, a veces indispensable capacidad para mezclar los elementos para prácticamente sin costo de rendimiento, así como para intercambiar objetos con otros std::list contenedores del mismo tipo en ninguna pérdida de rendimiento. Si usted necesita para barajar las cosas mucho, uso std::list.

    std::deque proporciona la constante de tiempo de inserción/extracción en la cabeza y la cola, pero la inserción en el medio puede ser bastante caro. Así que si usted necesita agregar/quitar cosas de la parte frontal como la parte trasera, std::deque podría ser lo que usted necesita.

    Cabe señalar que, gracias a moverse semántica, std::vector inserción rendimiento puede no ser tan malo como lo que solía ser. Algunas implementaciones implementado una forma de mover a la semántica de elementos basados en la copia (el llamado «swaptimization»), pero ahora que el movimiento es parte de la lengua, es exigido por la norma.

    No Asignaciones Dinámicas

    std::array es un buen contenedor de si desea que el menor número posible de asignaciones dinámicas. Es sólo una envoltura alrededor de una C-matriz; esto significa que su tamaño debe ser conocida en el en tiempo de compilación. Si usted puede vivir con eso, a continuación, utilizar std::array.

    Que se dice, utilizando std::vector y reserveing un tamaño funcionaría igual de bien para un almacén de std::vector. De esta manera, el tamaño real puede variar, y sólo se consigue una asignación de memoria (a menos que el golpe de la capacidad).

    • Bien, me gusta tu respuesta mucho también 🙂 WRT mantener un vector ordenado, aparte de std::sort, también hay std::inplace_merge que es interesante colocar fácilmente nuevos elementos (en lugar de una std::lower_bound + std::vector::insert llamada). Agradable para aprender acerca de flat_set y flat_map!
    • Usted también puede utilizar un vector con 16 bytes alineado tipos. También un buen reemplazo para vector<bool> es vector<char>.
    • también puede utilizar un vector con 16 bytes alineado tipos.» Dice que? Si std::allocator<T> no admite que la alineación (y no sé por qué no), entonces usted siempre puede usar su propio asignador personalizado.
    • porque std::vector::resize toma su tipo por valor, consulte stackoverflow.com/a/2340728/158259
    • C++11 de la std::vector::resize tiene una sobrecarga que no toma un valor (sólo se necesita el nuevo tamaño; los nuevos elementos serán defecto-construido en el lugar). También, ¿por qué son los compiladores incapaz de alinear correctamente los parámetros de valor, incluso cuando están declaró que la alineación?
    • Me golpea! Me alegro de c++11 fija la interfaz aunque
    • bitset para bool si usted sabe el tamaño de antemano en.cppreference.com/w/cpp/utility/bitset
    • no hace nada para solucionar este post advertencias acerca de vector<bool> dado que tiene los mismos problemas que: en realidad no contienen un conjunto de bool de los casos, más bien embalado bits accede a través del proxy de instancias de la clase que devolver un valor. En el contexto de esta pregunta, sólo la fuerza sobre la vector<bool> es que no está en posesión de un irremediablemente nombre engañoso y un sinfín de desprecio de todos los implicados en el lenguaje. Por cierto, en lugar de dar y uso de un deque para conseguir un verdadero contenedor de bools, podemos fácilmente crear un envoltorio estructura en torno a un bool instancia

  3. 1

    He aquí un rápido giro, aunque es probable que las necesidades de trabajo

    Should the container let you manage the order of the elements?
    Yes:
      Will the container contain always exactly the same number of elements? 
      Yes:
        Does the container need a fast move operator?
        Yes: std::vector
        No: std::array
      No:
        Do you absolutely need stable iterators? (be certain!)
        Yes: boost::stable_vector (as a last case fallback, std::list)
        No: 
          Do inserts happen only at the ends?
          Yes: std::deque
          No: std::vector
    No: 
      Are keys associated with Values?
      Yes:
        Do the keys need to be sorted?
        Yes: 
          Are there more than one value per key?
          Yes: boost::flat_map (as a last case fallback, std::map)
          No: boost::flat_multimap (as a last case fallback, std::map)
        No:
          Are there more than one value per key?
          Yes: std::unordered_multimap
          No: std::unordered_map
      No:
        Are elements read then removed in a certain order?
        Yes:
          Order is:
          Ordered by element: std::priority_queue
          First in First out: std::queue
          First in Last out: std::stack
          Other: Custom based on std::vector????? 
        No:
          Should the elements be sorted by value?
          Yes: boost::flat_set
          No: std::vector

    Puede observar que esta diferencia salvajemente desde el C++03 versión, principalmente debido al hecho de que yo realmente no me gusta enlaza los nodos. El enlazado de nodos contenedores generalmente se pueden superar en rendimiento por una persona no vinculada contenedor, excepto en raras situaciones. Si usted no sabe lo que esas situaciones son, y tienen acceso a aumentar, no uso vinculado nodo de contenedores. (std::list, std::slist, std::map, std::multimap, std::set, std::conjunto múltiple). Esta lista se centra principalmente en la pequeña y mediana cara de contenedores, debido a que (a) que el 99.99% de lo que nos ocupamos en el código, y (B) un Gran número de elementos necesidad de algoritmos personalizados, no diferentes contenedores.

Kommentieren Sie den Artikel

Bitte geben Sie Ihren Kommentar ein!
Bitte geben Sie hier Ihren Namen ein

Recent Articles

Python «set» con duplicados/elementos repetidos

Hay una forma estándar de representar un "conjunto" que puede contener elementos duplicados. Como yo lo entiendo, un conjunto tiene exactamente un cero o...

Python: generador de expresión vs rendimiento

En Python, ¿hay alguna diferencia entre la creación de un generador de objetos a través de un generador de expresión versus el uso de...

Cómo exportar/importar la Masilla lista de sesiones?

Hay una manera de hacer esto? O tengo que tomar manualmente cada archivo de Registro? InformationsquelleAutor s.webbandit | 2012-10-23

no distingue mayúsculas de minúsculas coincidentes en xpath?

Por ejemplo, para el xml a continuación <CATALOG> <CD title="Empire Burlesque"/> <CD title="empire burlesque"/> <CD...