c++ c++11 gcc visual-studio-2013

c++ - problema emplace_back() bajo VS2013



c++11 gcc (2)

Este es un problema en VS2013 y VS2015 cuando se emplaza un elemento en un vector que contiene el elemento. Si el vector cambia de tamaño, la referencia al elemento que se inserta no es válida. El trabajo consiste en crear una copia del elemento en el inserto, luego insértelo.

auto n = nums[0]; nums.emplace_back(n);

La llamada _Reservar está allí para garantizar que haya algo de memoria asignada para el vector (por lo que no es necesario verificarla en operaciones posteriores).

Considere los siguientes códigos

std::vector<int> nums{21, 22, 23, 24}; nums.emplace_back(nums[0]); nums.emplace_back(nums[1]); for (auto n : nums) { std::cout << n << std::endl; }

Salida de VS2013

21 22 23 24 -17891602 22

¿Por qué el -17891602 está aquí?

La salida de GCC 4.8.4 es correcta como sigue

21 22 23 24 21 22

Luego comparo la implementación de emplace_back entre VS2013 y GCC

VS2013

template<class... _Valty> void emplace_back(_Valty&&... _Val) { // insert by moving into element at end if (this->_Mylast == this->_Myend) _Reserve(1); _Orphan_range(this->_Mylast, this->_Mylast); this->_Getal().construct(this->_Mylast, _STD forward<_Valty>(_Val)...); ++this->_Mylast; }

GCC

template<typename _Tp, typename _Alloc> template<typename... _Args> void vector<_Tp, _Alloc>:: emplace_back(_Args&&... __args) { if (this->_M_impl._M_finish != this->_M_impl._M_end_of_storage) { _Alloc_traits::construct(this->_M_impl, this->_M_impl._M_finish, std::forward<_Args>(__args)...); ++this->_M_impl._M_finish; } else _M_emplace_back_aux(std::forward<_Args>(__args)...); }

Parece la extraña _Reserve(1); Se utiliza en VS2013 . ¿Por qué?

Editar:

El valor hex de -17891602 es 0xFEEEFEEE , que significa

Utilizado por la depuración HeapFree () de Microsoft para marcar la memoria del montón liberado

refiérase al número mágico

Luego depuré los códigos anteriores línea por línea y encontré el 0XFEEEFEEE causado por _Reserve(1); invocado


El problema de emplace

Los objetos vinculados al paquete de parámetros de función de la función miembro emplace no serán elementos o subobjetos de elementos del contenedor.

El emplace_back() se llama en la función VS2013 emplace() bajo VS2013 .

template<class... _Valty> iterator emplace(const_iterator _Where, _Valty&&... _Val) { // insert by moving _Val at _Where size_type _Off = _VIPTR(_Where) - this->_Myfirst; #if _ITERATOR_DEBUG_LEVEL == 2 if (size() < _Off) _DEBUG_ERROR("vector emplace iterator outside range"); #endif /* _ITERATOR_DEBUG_LEVEL == 2 */ emplace_back(_STD forward<_Valty>(_Val)...); _STD rotate(begin() + _Off, end() - 1, end()); return (begin() + _Off); }

Encontré una buena post , que describe algunos detalles de la implementación emplace_back() bajo VS2013 .

std::vector class tiene diferentes miembros de instancia (tanto regulares como internos) y entre ellos se encuentran los siguientes:

  • _Myfirst - apunta al comienzo de la matriz de datos
  • _Mylast - apunta al primer elemento sin inicializar en la matriz de datos. Si es igual a _Miend, la siguiente inserción causará la reasignación. Tienes a este tipo al end() llamada
  • _Myend - apunta al final de la matriz de datos

Entonces, en términos de direcciones de memoria, tiene lugar la siguiente desigualdad:

_Myfirst <=<= _Mylast <=<= _Myend

¿Ves esa línea con _Reserve(1) en ella? Esta llamada de función hace que nuestro error se revele.

Trabajemos paso a paso (consulte la función de ejemplo anterior).

nums.emplace_back(nums[0]);

Primero obtenemos una referencia al artículo porque el operator[] devuelve una reference

reference operator[](size_type _Pos) { ... }

Luego pasamos al método emplace_back , pasando una referencia nueva y válida al elemento que queremos insertar. Lo que vemos inmediatamente al principio es una verificación del tamaño del vector que excede. Mientras nuestra inserción haga que un vector crezca su tamaño, obtendremos una referencia invalidada justo después de que ocurra la reasignación . Esa es la razón de un comportamiento tan interesante pero esperado (una vez que llegamos a la implementación).