Внимательно читайте законы:
20.2.2 своп [utility.swap]
- template void swap(T& a, T& b) noexcept(is_nothrow_move_constructible::value &&
is_nothrow_move_assignable::value); 2 Требуется: тип T должен быть MoveConstructible и MoveAssignable. (Таблица 20) и (Таблица 22) 3 Эффекты: Обмен значениями, хранящимися в двух местах.
- template void swap(T (&a)[N], T (&b)[N]) noexcept(noexcept(swap(*a, *b))); 4 Требуется: a[i] должен быть заменен на b[i] для всех i в диапазоне [0,N). (17.6.3.2) 5 Эффекты: swap_ranges(a, a + N, b)
25.3.3 подкачка [alg.swap]
- шаблон недействителен iter_swap (ForwardIterator1 a, ForwardIterator2 b); 5 эффектов: поменять местами (*a, *b). 6 Требует: a и b должны быть разыменуемыми. *a можно заменить на *b. (17.6.3.2)
Таким образом, iter_swap требуется для обмена значениями, хранящимися в двух разыменованных местоположениях или диапазонах разыменованных местоположений, и любая попытка обмена самими ссылками или местоположениями ведет к борьбе с соответствием. Это явно исключает предположения о том, что оптимизация является причиной, лежащей в основе std::iter_swap. Вместо этого, как верно заметил Картофель, инкапсуляция и абстракция являются основными причинами его существования. std::iter_swap и std::swap принадлежат к разным уровням абстракции, точно так же различаются сама std::swap и любая двоичная функция, не являющаяся членом, с именем «swap», выбранная с помощью разрешения перегрузки.
Поменять местами роли разработчика и дизайнера, чтобы понять, что достижение одного и того же результата не означает, что они одинаковы, как в «даже объявление typedef из фундаментального типа - это просто шум для компилятора, это не шум для читателя». Воспринимайте это как шутку, но мы могли бы утверждать, что весь C++ — это просто устаревший артефакт, обертывающий C, поскольку оба делают одно и то же, находясь на самом низком уровне, и так далее с любым блоком кода, представляющим абстракцию от другого с помощью оболочки. Особенно, когда линия такая тонкая, как в случае std::iter_swap, "swap" и std::swap. Возможно, «использование std::swap» имеет всего несколько символов и исчезает после компиляции, но означает введение идентификатора и создание целого механизма разрешения перегрузок. Вводили снова и снова, строили снова и снова, заменяли снова и снова, отбрасывали снова и снова. Вдали от абстрактного, инкапсулированного и переработанного подхода.
Обнажение внутренней работы через верхний слой дает дополнительный потенциальный шанс отказа при обслуживании. В домене подкачки отсутствие (или испорченное) «использование std::swap» в дизайне сдерживания глубокого метапрограммирования будет молча ждать внутри вашей функции шаблона, ожидая тривиально заменяемого, фундаментального типа или типа c-массива, чтобы сломать сборку, если lucky или даже StackOverflow(TM) с помощью бесконечной рекурсии. Очевидно, что реализация расширяемого механизма должна быть опубликована, но также должна соблюдаться. Что касается тривиальной замены, обратите внимание, что любой moveconstructible и moveassignable может быть заменен на свой собственный тип, даже если в нем отсутствует перегруженный хук разрешения подкачки, и действительно существуют неясные методы для отключения нежелательного поведения подкачки.
Имея это в виду, возможно, все это может быть продолжено в неправильной интерпретации самого идентификатора std::iter_swap: он означает не «подкачка итератора», а «итерируемая подкачка». Не дайте себя обмануть стандартными требованиями к аргументам, являющимся прямыми итераторами: по сути, указатель — это итератор с произвольным доступом, таким образом удовлетворяющий требованиям. Физически вы проходите по указателю, логически вы проходите через итератор. Комиссия обычно пытается указать минимальные требования для работы объекта с определенным и ожидаемым поведением, не более того. Название «итерируемая подкачка» правильно раскрывает цель и возможности механизма. идентификатор "std::iter_swap" кажется не из-за возникшей путаницы, но уже слишком поздно менять его и отменять всю основанную на нем кодовую базу.
Не стесняйтесь менять местами, пока это работает, но, пожалуйста, не на моих часах. Смешивание слоев абстракции не заставит компилятор плакать, но интерфейсы слишком круты, чтобы их избегать. Вместо этого вот фрагмент, который поможет вам в будущем:
//#include <utility> // std::swap is not required here
#include <algorithm> // std::iter_swap is
namespace linker {
class base {
};
class member {
};
template<class M = member, class B = base> // requires swappable base and member
class link : B {
public:
void swap(link &other) { // using iterable swapping
std::iter_swap(static_cast<B*>(this), static_cast<B*>(&other));
std::iter_swap(&_member, &other._member);
}
private:
M _member;
};
template<class base, class member>
void swap(link<base,member>& left, link<base,member>& right) { // extending iterable swapping
left.swap(right);
}
}
namespace processor {
template<class A, class B>
void process(A &a, B &b) { // using iterable swapping
std::iter_swap(&a, &b);
}
}
int main() {
#if !defined(PLEASE_NO_WEIRDNESS)
typedef
linker::link<
linker::link<
linker::link< int[1] >,
linker::link< void*, linker::link<> >
>[2],
linker::link<
linker::member[3]
>
>
swappable[4]; // just an array of n-ary hierarchies
#else
typedef linker::link<> swappable;
#endif
swappable a, b;
processor::process(a, b);
}
Некоторые интересные моменты в качестве дополнительного руководства:
Обмен означает выбрасывание исключений. Заявление кажется глупым, но это не тот случай, когда вы знаете, что идиома подкачки ориентирована не на производительность, а на исключительную безопасность и надежность.
std::iter_swap демонстрирует одну из многих прекрасных, но недооцененных особенностей метапрограммирования: шаблон выполняет не только разрешение перегрузки, но и разрешение пространства имен, что позволяет использовать его как первое в цепочке неизвестных и несвязанных пространств имен. Спасибо, одной проблемой меньше.
Заменяемые требования позволяют вам использовать std::swap напрямую, если (и ТОЛЬКО ЕСЛИ) вы можете позволить предположить, что обе цели относятся к фундаментальным типам или c-array к фундаментальным типам, что позволяет компилятору обходить любое разрешение перегрузки. К сожалению, это исключает параметры почти каждого шаблона. Использование std::swap напрямую подразумевает, что обе цели относятся к одному типу (или принудительно относятся к одному типу).
Не тратьте усилия на объявление заменяемых возможностей для типа, который уже тривиально заменяется сам с собой, как и наш класс шаблона ссылки (попробуйте удалить linker::swap, поведение совсем не изменится).
«swap» был разработаны с возможностью расширения для переключения между различными типами,
автоматически для одного и того же типа. Имейте в виду, что тип не является "заменяемым" или
"не заменяемым" сам по себе, а "заменяемым-с" или
"незаменяемым-с" другим типом.
Наконец, мне интересно, сколько читателей заметят
и признать, что утилита не является алгоритмом. В реализации Microsoft-Dinkumware, среди прочего, std::iter_swap просто находится в неправильном заголовке для удобства, что не так. Может просто его идентификатор есть.
Редактировать: Столкнувшись с некоторыми другими связанными ошибками, я подумал, что могу обобщить их так: алгоритм - это концепция настолько общая и конкретная, что каждый раз, когда кто-то собирается специализировать одну из них, дизайнер плачет где-то еще. В случае std::iter_swap, поскольку комитет явно не дает никакой свободы, любая попытка настроить алгоритм, как в предположениях о повторном связывании, заслуживает другого значения и идентификатора. Также, возможно, кто-то пропустил, что у контейнеров есть функция-член подкачки, где применяются оптимизации.
Лучший рефакторинг, чтобы ваши конечные объекты слоя были неданными, фундаментальными или представляли скрытые более тяжелые объекты (потоковые, если они достаточно тяжелые). Примите во внимание, что привлечение ресурсов должно быть инициализировано (RAII) и как перегрузки new-delete, так и распределители контейнеров имеют использование, чтобы раскрыть настоящие преимущества обмена без дополнительных усилий. Оптимизируйте ресурсы, чтобы перемещать данные только при запросе, а затем позвольте C++ создавать ваши типы легко, безопасно и быстро по умолчанию.
Девиз: В старые времена люди боролись с данными, которые были слишком большими в памяти и слишком медленными на диске. В настоящее время векторы итераторов фильтруются из пулов хранения и передаются для обработки в параллельных каналах. Завтра машины будут ездить одни. Заслуживает PostIt.
person
tadevt
schedule
26.05.2013
iter_swap
никогда не может повторно связать узлы связанного списка, потому что тогда пользователь, удерживающий итератор в связанном списке, увидит, что содержимое заменено наswap(*a, *b)
, но не наiter_swap(a, b)
, что противоречит требованию, чтоiter_swap(a, b)
должен вести себя какswap(*a, *b)
. Ну а желательно ли это - совсем другой вопрос... - person Marc Mutz - mmutz   schedule 20.07.2015std::iter_swap
для этого специального типа итератора, а не перегружать искусственныйstd::swap
для значений или аргументов r-значения. . - person alfC   schedule 06.11.2016iter_swap
ericniebler.com/2015/02 /03/итераторы-плюс-плюс-часть-1 - person Predelnik   schedule 13.03.2018