Этот вопрос основан на обсуждении ниже недавнего блога Скотта Майера.
Кажется "очевидным", что std::swap(x, x)
должен оставить x
неизменным как в С++ 98, так и в С++ 11, но я не могу найти никаких гарантий этого эффекта ни в стандарте. С++ 98 определяет std::swap
в терминах построения копии и назначения копии, тогда как С++ 11 определяет ее в терминах построения перемещения и назначения переноса, и это кажется уместным, потому что в С++ 11 (и С++ 14), 17.6.4.9 говорит, что назначение переноса не должно быть безопасным для самостоятельного назначения:
Если аргумент функции связывается с параметром ссылки rvalue, реализация может предположить, что этот параметр является уникальной ссылкой на этот аргумент.... [Примечание: если программа передает значение l xvalue при передаче этого lvalue в библиотечную функцию (например, вызывая функцию с аргументом move (x)), программа эффективно просит эту функцию относиться к этому lvalue как временному. реализация может свободно оптимизировать пропуски наложения псевдонимов, которые могут потребоваться, если аргумент был lvalue. -end note]
Отчет о дефекте , который породил эту формулировку, делает очевидным следующее:
это поясняет, что операторы присваивания перемещения не должны выполнять традиционный, если (этот!= & rhs) тест, обычно найденный (и необходимый) в операциях присваивания копий.
Но в С++ 11 и С++ 14 ожидается, что std::swap
использует эту реализацию,
template<typename T>
void swap(T& lhs, T& rhs)
{
auto temp(std::move(lhs));
lhs = std::move(rhs);
rhs = std::move(temp);
}
и первое присваивание выполняет присваивание себе, где аргумент является значением r. Если оператор присваивания переходов для T
следует политике стандартной библиотеки и не беспокоится о присвоении себе, это может показаться судом undefined, и это будет означать, что std::swap(x, x)
будет иметь UB, а также.
Это вызывает беспокойство даже в изоляции, но если мы предположим, что std::swap(x, x)
должен был быть безопасным в С++ 98, это также означает, что С++ 11/14 std::swap
может молча сломать код С++ 98.
Итак, std::swap(x, x)
гарантированно оставляет x
неизменным? В С++ 98? В С++ 11? Если да, то как это взаимодействует с разрешением 17.6.4.9 для присваивания переадресации, чтобы он не был безопасным для самостоятельного назначения?