Переместить семантику = = пользовательская функция swap устарела?
недавно много вопросы поп о том, как обеспечить собственную . С C++11, std::swap использовать std::move и переместите семантику, чтобы как можно быстрее поменять заданные значения. Это, конечно, работает, только если вы предоставляете конструктор перемещения и оператор назначения перемещения (или тот, который использует pass-by-value).
теперь, с учетом этого, на самом деле необходимо написать свой собственный swap функции в C++11? Я мог только подумайте о неподвижных типах, но опять же, custom swaps обычно работают через какой-то" обмен указателями " (он же перемещение). Может быть, с определенными ссылочными переменными? Хм...
5 ответов
это вопрос суда.  Я обычно позволяю std::swap выполните задание для прототипирования кода, но для кода выпуска напишите пользовательский своп.  Обычно я могу написать пользовательский своп, который примерно в два раза быстрее, чем 1 move construction + 2 move assignments + 1 resourceless destruction.  Однако можно подождать, пока std::swap на самом деле оказывается проблемой производительности, прежде чем беспокоиться.
обновление для Alf P. Steinbach:
20.2.2 [утилита.своп] указывает, что std::swap(T&, T&) есть noexcept эквивалентно:
template <class T>
void
swap(T& a, T& b) noexcept
                 (
                    is_nothrow_move_constructible<T>::value &&
                    is_nothrow_move_assignable<T>::value
                 );
т. е. если переместить операции на T are noexcept, потом std::swap on T is noexcept.
обратите внимание, что эта спецификация не требует от членов.  Это требует только, чтобы конструкция и назначение из rvalues существовали, и если это noexcept, тогда своп будет noexcept.  Например:
class A
{
public:
    A(const A&) noexcept;
    A& operator=(const A&) noexcept;
};
std::swap<A> является noexcept, даже без членов move.
могут быть некоторые типы, которые можно поменять местами, но не перемещать. Я не знаю никаких неподвижных типов, поэтому у меня нет никаких примеров.
по соглашению обычай swap предлагает гарантию не-хода. Я не знаю, о std::swap. У меня сложилось впечатление, что работа комитета по этому вопросу носит политический характер, поэтому меня не удивило бы, если бы они где-то определили ... --2--> as bug, или аналогичные политические маневры игры слов. Поэтому я бы не стал полагаться на ответ тут если он не обеспечивает подробный удар, ударяя цитатой из C++0x to-be-standard, до мельчайших деталей (чтобы быть уверенным, что нет bug).
конечно, вы можете реализовать swap как
template <class T>
void swap(T& x, T& y)
{
  T temp = std::move(x);
  x = std::move(y);
  y = std::move(temp);
}
но у нас может быть свой класс, скажем A, который мы можем поменять более быстро.
void swap(A& x, A& y)
{
  using std::swap;
  swap(x.ptr, y.ptr);
}
который, вместо того, чтобы запускать конструктор и деструктор, просто меняет местами указатели (которые вполне могут быть реализованы как XCHG или что-то подобное).
конечно, компилятор может оптимизировать вызовы конструктора/деструктора в первом примере, но если у них есть побочные эффекты (т. е. вызовы new/delete), это возможно, недостаточно умен, чтобы оптимизировать их.
рассмотрим следующий класс, который содержит выделенный для памяти ресурс (для простоты, представленный одним целым числом):
class X {
    int* i_;
public:
    X(int i) : i_(new int(i)) { }
    X(X&& rhs) noexcept : i_(rhs.i_) { rhs.i_ = nullptr; }
 // X& operator=(X&& rhs) noexcept { delete i_; i_ = rhs.i_;
 //                                  rhs.i_ = nullptr; return *this; }
    X& operator=(X rhs) noexcept { swap(rhs); return *this; }
    ~X() { delete i_; }
    void swap(X& rhs) noexcept { std::swap(i_, rhs.i_); }
};
void swap(X& lhs, X& rhs) { lhs.swap(rhs); }
затем std::swap результаты удаление нулевого указателя 3 раза (как двигаться оператор присваивания и объединяющий оператор присваивания случаях). Компиляторы могут иметь проблемы с оптимизацией такого delete см. https://godbolt.org/g/E84ud4.
таможня swap не вызывает каких-либо delete и, следовательно, может быть более эффективным. Я думаю, это причина, почему std::unique_ptr обеспечивает пользовательскую std::swap специализация.
обновление
кажется, что компиляторы Intel и Clang могут оптимизировать удаление нулевых указателей, однако GCC нет. См.почему GCC не оптимизирует удаление нулевых указателей в C++? для сведения.
обновление
это кажется, что с GCC мы можем предотвратить вызов delete оператора путем переписывания X следующим образом:
 // X& operator=(X&& rhs) noexcept { if (i_) delete i_; i_ = rhs.i_;
 //                                  rhs.i_ = nullptr; return *this; }
    ~X() { if (i_) delete i_; }