c++ - programacion - ¿Por qué es imposible asignar un vector de objetos que carecen de operador de copia?
matriz de cadenas en c (3)
Puede encontrar esta función informativa, de libc ++. En particular, tenga en cuenta la llamada a std::copy
.
template <class _Tp, class _Allocator>
template <class _ForwardIterator>
typename enable_if
<
__is_forward_iterator<_ForwardIterator>::value &&
is_constructible<
_Tp,
typename iterator_traits<_ForwardIterator>::reference>::value,
void
>::type
vector<_Tp, _Allocator>::assign(_ForwardIterator __first, _ForwardIterator __last)
{
size_type __new_size = static_cast<size_type>(_VSTD::distance(__first, __last));
if (__new_size <= capacity())
{
_ForwardIterator __mid = __last;
bool __growing = false;
if (__new_size > size())
{
__growing = true;
__mid = __first;
_VSTD::advance(__mid, size());
}
pointer __m = _VSTD::copy(__first, __mid, this->__begin_);
if (__growing)
__construct_at_end(__mid, __last, __new_size - size());
else
this->__destruct_at_end(__m);
}
else
{
deallocate();
allocate(__recommend(__new_size));
__construct_at_end(__first, __last, __new_size);
}
}
operator =
just calls assign(r.begin(), r.end())
después de arreglar el asignador si difieren.
Tengo un vector de estructuras que son copiables, pero no asignables:
struct Struct
{
inline Struct(const std::string& text, int n) : _text(text), _n(n) {}
inline Struct(const Struct& other) : _text(other._text), _n(other._n) {}
const std::string _text;
const int _n;
Struct& operator=(const Struct&) = delete;
};
Todo funcionó bien. De hecho, incluso podría pasar el std::vector<Struct>
por valor como valor de retorno de una función. Y sin embargo, esto falla:
std::vector<TextFragment> v1, v2;
v2 = v1;
El error, por supuesto, es:
error: C2280: ''Struct & Struct :: operator = (const Struct &)'': intentando hacer referencia a una función eliminada
No entiendo por qué trata de invocar eso. ¿Es eso una especie de optimización para evitar la reasignación del bloque de memoria del vector?
Un std::vector
es un contenedor con capacidad de asignación. Si miramos las especificaciones para eso (tabla 99) tenemos a = t
donde a
es un valor a = t
no const t
es un valor lvalue o const y requiere
T es CopyInseable en X y CopyAssignable . publicación: a == t
Énfasis mío
Donde T
es el value_type
de X
(el contenedor). También establece que la operación es lineal. Como T
debe ser CopyAssignable y Struct
no es CopyAssignable, no es necesario que funcione.
Esto implica que la operación de asignación sería algo así como:
std::vector<T>& operator=(const std::vector<T>& rhs)
{
// allocate enough room for data if needed
for (std::size_t i = 0; i < rhs.size(); ++i)
data[i] = rhs.data[i];
return *this;
}
¿Es eso una especie de optimización para evitar la reasignación del bloque de memoria del vector?
Casi. Es una optimización para evitar la reasignación de cualquier bloque de memoria que pueda estar presente en value_type
vector
. Es decir, es una suposición global que la asignación puede ser más eficiente que la destrucción seguida de la construcción de copias.
Por ejemplo, considere la asignación vector<string>
, para dos vector
igual tamaño s, y un grupo de string
de igual tamaño s en cada punto del vector
:
v2 = v1;
Toda esta operación tiene que hacer es memcpy
cada string
. Sin asignaciones en absoluto. La reducción de asignaciones / desasignaciones es una de las optimizaciones más importantes que existen en la actualidad.
Sin embargo, no todo está perdido para tu Struct
. Lo que quiere hacer es indicar al vector
que no desea asignar sus Struct
s, sino que debe destruirlos y luego copiarlos desde v1
. La sintaxis para hacer esto es:
v2.clear();
for (const auto& x : v1)
v2.push_back(x);
Como se señala en los comentarios a continuación, también puede copiar el constructo v1
, y luego swap
con la copia. O necesita crear una copia local temporal de v1
, o necesita usar v1
en el "lhs" de intercambio de miembros:
std::vector<Struct>(v1).swap(v2);
Personalmente, me resulta difícil de leer. En C ++ 11/14 prefiero esta alternativa que implica la asignación de movimiento:
v2 = std::vector<Struct>(v1);
Estas alternativas son más fáciles para los ojos. Pero la primera alternativa, usar clear()
y push_back
va a ser la más eficiente en promedio. Esto se debe a que la primera alternativa es la única que tiene la posibilidad de reutilizar la capacity()
en v2
. Los otros dos siempre recrean nueva capacity()
en la copia de v1
y descartan la capacity()
existente de v2
capacity()
.