Это в дополнение к ответу Терри.
Причина, по которой нам пришлось сделать swap
функции в C ++ до 0x, заключается в том, что общая свободная функция std::swap
была менее эффективной (и менее универсальной), чем могла бы быть. Он сделал копию параметра, затем имел два переназначения, а затем выпустил по существу потерянную копию. Создание копии тяжеловесного класса - пустая трата времени, когда мы, программисты, знаем, что нам действительно нужно поменять местами внутренние указатели и еще много чего.
Однако, rvalue-ссылки полностью избавляют от этого. В C ++ 0x swap
реализовано как:
template <typename T>
void swap(T& x, T& y)
{
T temp(std::move(x));
x = std::move(y);
y = std::move(temp);
}
В этом гораздо больше смысла. Вместо того, чтобы копировать данные, мы просто перемещаем данные. Это позволяет даже не копируемые типы, такие как потоки, обмениваться. В проекте стандарта C ++ 0x говорится, что для того, чтобы типы могли поменяться местами с std::swap
, они должны иметь возможность конструирования rvalue и присваивания rvalue (очевидно).
Эта версия swap
по существу будет делать то же, что и любая пользовательская функция подкачки. Рассмотрим класс, для которого мы обычно пишем swap
(например, этот «тупой» вектор):
struct dumb_vector
{
int* pi; // lots of allocated ints
// constructors, copy-constructors, move-constructors
// copy-assignment, move-assignment
};
Ранее swap
делал бы избыточную копию всех наших данных, прежде чем потом их отбрасывать. Наша пользовательская функция swap
просто меняет указатель, но в некоторых случаях может быть неудобной для использования. В C ++ 0x перемещение достигает того же конечного результата. Вызов std::swap
сгенерирует:
dumb_vector temp(std::move(x));
x = std::move(y);
y = std::move(temp);
Что означает:
dumb_vector temp;
temp.pi = x.pi; x.pi = 0; // temp(std::move(x));
x.pi = y.pi; y.pi = 0; // x = std::move(y);
y.pi = temp.pi; temp.pi = 0; // y = std::move(temp);
Компилятор, конечно, избавится от избыточных назначений, оставляя:
int* temp = x.pi;
x.pi = y.pi;
y.pi = temp;
То есть точно , что наш обычай swap
сделал бы в первую очередь. Поэтому, хотя до C ++ 0x я бы согласился с вашим предложением, пользовательские swap
больше не нужны, с введением rvalue-ссылок. std::swap
будет отлично работать в любом классе, который реализует функции перемещения.
На самом деле, я бы сказал, что реализация функции swap
должна стать плохой практикой. Любому классу, которому нужна функция swap
, также потребуются функции rvalue. Но в этом случае просто нет необходимости в беспорядке кастома swap
. Размер кода действительно увеличивается (две функции ravlue против одной swap
), но ссылки на rvalue применяются не только для обмена, что дает нам положительный компромисс. (В целом более быстрый код, более понятный интерфейс, немного больше кода, больше никаких проблем swap
ADL.)
Что касается того, можем ли мы default
rзначить функции, я не знаю. Я посмотрю это позже, или, может быть, кто-то другой может вмешаться, но это наверняка будет полезно. :)
Несмотря на это, имеет смысл разрешить default
функции-значения вместо swap
. Таким образом, по сути, если они допускают функции = default
rvalue, ваш запрос уже выполнен. :)
РЕДАКТИРОВАТЬ: Я немного поискал, и предложение о = default
переезде было предложением n2583
. Согласно этому (который я не знаю, как читать очень хорошо), оно было "возвращено". Он указан в разделе «Не готов к C ++ 0x, но открыт для повторной отправки в будущем». Похоже, он не будет частью C ++ 0x, но может быть добавлен позже.
Несколько разочаровывает. (
РЕДАКТИРОВАТЬ 2: оглянувшись немного побольше, я обнаружил следующее: Определение специальных функций Move Move , что намного новее и похоже, что мы можем по умолчанию move
. Ура!