Это безопасно, потому что во время операции подкачки ничего не создается. Только члены данных класса std::vector
меняются местами.
Рассмотрим следующую демонстрационную программу, которая проясняет, как объекты класса std::vector
меняются местами.
#include <iostream>
#include <utility>
#include <iterator>
#include <algorithm>
#include <numeric>
class A
{
public:
explicit A( size_t n ) : ptr( new int[n]() ), n( n )
{
std::iota( ptr, ptr + n, 0 );
}
~A()
{
delete []ptr;
}
void swap( A & a ) noexcept
{
std::swap( ptr, a.ptr );
std::swap( n, a.n );
}
friend std::ostream & operator <<( std::ostream &os, const A &a )
{
std::copy( a.ptr, a.ptr + a.n, std::ostream_iterator<int>( os, " " ) );
return os;
}
private:
int *ptr;
size_t n;
};
int main()
{
A a1( 10 );
A a2( 5 );
std::cout << a1 << '\n';
std::cout << a2 << '\n';
std::cout << '\n';
a1.swap( a2 );
std::cout << a1 << '\n';
std::cout << a2 << '\n';
std::cout << '\n';
return 0;
}
Выход программы
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4
0 1 2 3 4
0 1 2 3 4 5 6 7 8 9
Как видите, только члены данных ptr
и n
поменялись местами в функции swap. Дополнительные ресурсы не используются.
Аналогичный подход используется в классе std::vector
.
Что касается этого примера
std::vector<Widget> WidgetVector;
std::vector<Widget2> Widget2Vector;
тогда есть объекты разных классов. Функция-член swap применяется к векторам одного типа.
Да, это совершенно безопасно для обмена векторов одного типа.
Vector под капотом - это всего лишь несколько указателей, указывающих на данные, которые использует вектор, и «конец» последовательности. Когда вы вызываете swap, вы просто обмениваетесь указателями между векторами. Вам не нужно беспокоиться о том, что векторы имеют одинаковый размер из-за этого.
Векторы разных типов нельзя поменять местами
swap
. Вам нужно будет реализовать свою собственную функцию, которая выполняет преобразование и обмен.источник
2
. Обновлено.Да. Обмен, как правило, можно считать безопасным. С другой стороны, безопасность субъективна и относительна и может рассматриваться с разных точек зрения. Таким образом, невозможно дать удовлетворительный ответ, не дополняя вопрос контекстом и не выбирая, какой вид безопасности рассматривается.
Там не будет UB. Да, это все еще безопасно в том смысле, что программа плохо сформирована.
источник
swap
Функция определяется следующим образом :void swap( T& a, T& b );
. Обратите внимание, что обаa
иb
(и должны быть) одного типа . (Для этой сигнатуры не определена такая функция:void swap( T1& a, T2& b )
это не имеет смысла!)Аналогично,
swap()
функция-членstd::vector
класса определяется следующим образом:Теперь, поскольку не существует «эквивалентного» определения с переопределением шаблона (см. Явные специализации шаблонов функций ) для параметра функции (который будет иметь форму:)
template <typename T2> void swap(std::vector<T2>& other)
, этот параметр должен быть вектором того же типа (шаблона), что и «вызывающий» класс (то есть он также должен бытьvector<T1>
).Ваши
std::vector<Widget>
иstd::vector<Widget2>
два различных типа, так что вызовswap
не будет компилировать, попробуйте ли использовать функцию - член либо объект (как ваш код делает), или с помощью специализации вstd::swap()
функции , которая принимает дваstd:vector
объектов в качестве параметров.источник
std::vector::swap
такое функция-член, как это может быть специализация автономной функции шаблона ???std::swap
, это не то, что использует OP. Когда вы это делаетеFirst.swap(Second);
, вы вызываетеstd::vector::swap
функцию, отличную отstd::swap
void swap(std::vector& other)
(то естьstd::vector<T>
), а не какtemplate <typename U> void swap(std::vector<U>& other)
(при условии, что T является параметром типа для самого вектора).Вы не можете менять векторы двух разных типов, но это ошибка компиляции вместо UB.
vector::swap
принимает только векторы одного типа и распределителя.Не уверен, что это сработает, но если вам нужен вектор, содержащий
Widget2
s, преобразованный изWidget
s, вы можете попробовать это:Widget2
должно быть двигаться от конструктиваWidget
.источник
using std::swap; swap(a, b);
иa.swap(b);
имеют точно такую же семантику, где работает последняя; по крайней мере для любого вменяемого типа. Все стандартные типы в этом отношении нормальны.Если вы не используете интересный распределитель (то есть с состоянием, не всегда равным и не распространяемый при замене контейнера, см.
std::allocator_traits
), Замена двухstd::vector
s с одинаковыми аргументами шаблона - это просто скучный обмен трех значений (для емкости, размера и данных). указатель). А перестановка основных типов, отсутствующих гонок данных, безопасна и не может быть выброшена.Это даже гарантируется стандартом. См
std::vector::swap()
.источник