¿Se copia la capacidad en un vector?

5 minutos de lectura

avatar de usuario
usuario6426033

Tome el siguiente código:

std::vector<int> a;
a.reserve(65536);
std::vector<int> b(a);  //NOTE: b is constructed from a

a.reserve(65536); // no reallocation
b.reserve(65536);

¿Se copia la capacidad? ¿Habrá una reasignación en la última línea? ¿La norma dice algo al respecto o es silenciosa?

  • En la documentación de vector c-tors, se afirma que copia elementos. es.cppreference.com/w/cpp/container/vector/vector

    – paweldac

    5 de junio de 2016 a las 7:26


  • Posible duplicado de la capacidad std::vector después de copiar

    – jww

    14 de octubre de 2018 a las 3:09


avatar de usuario
uh oh alguien necesita un cachorro

¿Se copia la capacidad?

En la práctica, no. Lo probé en línea en Clang y GCC tanto como MSVC y ninguno de ellos copia la capacidad.

¿Habrá una reasignación en la última línea?

Si la capacidad es menor que el argumento para reservar (es decir, no se copia), entonces sí.

¿La norma dice algo al respecto o es silenciosa?

No se proporcionan definiciones para el constructor de copia en vector.contras. En su lugar, tenemos que mirar el contenedor.requisitos

X denota una clase de contenedor que contiene objetos de tipo T, a y
b denotan valores de tipo X, u denota un identificador, r denota un valor no constante de tipo Xy rv denota un valor r no constante de tipo X.

X u(a)

X u = a;

Requiere: T es CopyInsertable dentro X (vea abajo).

correo: u == a

Ahora, ¿qué significa que dos contenedores sean iguales?

a == b

== es una relación de equivalencia. equal(a.begin(), a.end(), b.begin(), b.end())

En otras palabras, dado que no requiere capacity ser iguales en la comparación, entonces no hay razón para copiar el capacity.

  • @P0W No hay una manera fácil que pueda ver para vincular a una muestra de código directo en rextester.

    – uh oh alguien necesita un cachorro

    6 de junio de 2016 a las 4:27

avatar de usuario
AnatolyS

El estándar no dice nada sobre la preservación de la capacidad cuando llama al constructor de copias. Así que no tienes ninguna garantía al respecto.

Pero puede hacer el siguiente truco, que intercambia el estado de a y b, si necesita conservar la capacidad solo en la copia:

 std::vector<int> a;
 a.reserve(65536);
 std::vector<int> b(a);
 b.swap(a); // now b has a's state
 assert(b.capacity() == 65536); 

  • esto solo cambia cual reserve la llamada provocará una reasignación.

    – Saludos y hth. – alf

    5 de junio de 2016 a las 8:42

  • swap no hace nada con el asignador, intercambia solo el estado de los objetos.

    – AnatolyS

    5 de junio de 2016 a las 10:05

  • Entonces, ¿puedes intercambiar vectores que tengan diferentes asignadores? Si es así, no puede simplemente intercambiar la parte única de la memoria asignada.

    – JDługosz

    5 de junio de 2016 a las 10:22

  • @JDługosz Dos vectores con diferentes tipos de asignador son tipos de vectores diferentes, por lo que no puede intercambiarlos.

    – AnatolyS

    5 de junio de 2016 a las 10:36


  • @AnatolyS Esto no es cierto en C++ 11. En C ++ 03, los asignadores debían ser sin estado, por lo que la declaración “el intercambio no hace nada con los asignadores” es algo cierta. En C++11 el comportamiento de swap con respecto al asignador está personalizado por allocator_traits<Alloc>::propagate_on_container_swap.

    – sbabbi

    5 de junio de 2016 a las 12:10

avatar de usuario
Saludos y hth. – alf

No, no se garantiza que la capacidad sea preservada por un vector copiar la construcción.

Puedes hacerlo de la siguiente manera:

vector<int> b;
b.reserve( a.capacity() );
b = a;

Mejor encapsulado en una función.

avatar de usuario
Eisa N.

Bueno, una simple verificación como la siguiente revela que la capacidad no se copia:

std::vector<int> a;
a.reserve(65536);
cout << "a.capacity is " << a.capacity() << endl; // prints 65536

std::vector<int> b(a);  //NOTE: b is constructed from a
cout << "b.capacity is " << b.capacity() << endl; // prints 0

Creo que al copiar el vector a a bla capacidad de b se ajusta al tamaño de a en la mayoría de los compiladores; aunque esto no está garantizado.

avatar de usuario
terry

  1. Como se muestra a continuación en el código fuente del vector SGI STL, operador= reservará espacio para exactamente norte elementos, es decir _M_fin_de_almacenamiento = _M_inicio + __xlen;.
    template <class _Tp, class _Alloc>
    vector<_Tp,_Alloc>&
    vector<_Tp,_Alloc>::operator=(const vector<_Tp, _Alloc>& __x)
    {
      if (&__x != this) {
        const size_type __xlen = __x.size();
        if (__xlen > capacity()) {
          iterator __tmp = _M_allocate_and_copy(__xlen, __x.begin(), __x.end());
          destroy(_M_start, _M_finish);
          _M_deallocate(_M_start, _M_end_of_storage - _M_start);
          _M_start = __tmp;
          _M_end_of_storage = _M_start + __xlen;
        }
        else if (size() >= __xlen) {
          iterator __i = copy(__x.begin(), __x.end(), begin());
          destroy(__i, _M_finish);
        }
        else {
          copy(__x.begin(), __x.begin() + size(), _M_start);
          uninitialized_copy(__x.begin() + size(), __x.end(), _M_finish);
        }
        _M_finish = _M_start + __xlen;
      }
      return *this;
    }
  1. Como se muestra a continuación en el código fuente del vector SGI STL, los vectores copiar constructor reservará espacio para exactamente norte elementos, es decir _M_fin_de_almacenamiento = _M_inicio + __n;.
      template <class _InputIterator>
      vector(_InputIterator __first, _InputIterator __last,
             const allocator_type& __a = allocator_type()) : _Base(__a) {
        typedef typename _Is_integer<_InputIterator>::_Integral _Integral;
        _M_initialize_aux(__first, __last, _Integral());
      }

      template <class _Integer>
      void _M_initialize_aux(_Integer __n, _Integer __value, __true_type) {
        _M_start = _M_allocate(__n);
        _M_end_of_storage = _M_start + __n;
        _M_finish = uninitialized_fill_n(_M_start, __n, __value);
      }

¿Ha sido útil esta solución?