Ответ 1
Нет, это не поведение undefined, это будет определенное поведение реализации, оно будет зависеть от того, как реализовано назначение переноса.
Соответственно этому LWG issue 2468: Self-move-назначение типов библиотек, обратите внимание, что это активная проблема и не имеет официального предложения, поэтому это должно считаются ориентировочными, а не окончательными, но он указывает разделы, которые участвуют в стандартной библиотеке, и указывает, что они в настоящее время конфликтуют. В нем говорится:
Предположим, что мы пишем
vector<string> v{"a", "b", "c", "d"}; v = move(v);
Каким должно быть состояние v? В стандарте ничего не сказано специфические для самодвижения-назначения. Там соответствующий текст в нескольких части стандарта, и неясно, как их согласовать.
[...]
Из текста не видно, как свести эти штуки вместе, потому что не ясно, какой из них имеет преимущество. Возможно, 17.6.4.9 [res.on.arguments] выигрывает (он налагает неявное предварительное условие, которое не упоминается в требованиях MoveAssignable, поэтому v = move (v) есть undefined), или, может быть, 23.2.1 [container.requirements.general] (он явно дает дополнительные гарантии для Container:: operator = за пределами того, что гарантировано для библиотечных функций в целом, поэтому v = move (v) является no-op) или, возможно, что-то еще.
В существующих реализациях, которые я проверил, для чего это стоит, v = move (v) появился, чтобы очистить вектор; он не оставил вектор неизменным и не вызвал крушения.
и предлагает:
Неофициально: измените таблицы требований MoveAssignable и Container (и любые другие таблицы требований, которые упоминают назначение переноса, если они есть), чтобы сделать его явным, что x = move (x) определено поведение и оно оставляет x в действительном, но неуказанном состоянии, Вероятно, это не то, что сегодня говорится в стандарте, но это, вероятно, то, что мы намеревались, и оно согласуется с тем, что мы сказали пользователям и с какими реализациями на самом деле.
Примечание. Для встроенных типов это в основном копия, мы можем видеть из стандартной секции С++ 14 5.17
[expr.ass]:
В простом присваивании (=) значение выражения заменяет значение объекта, на которое ссылается левый операнд.
который отличается от случая для классов, где 5.17
говорит:
Если левый операнд имеет тип класса, класс должен быть полным. Назначение объектам класса определено оператором присваивания копирования/перемещения (12.8, 13.5.3).
Примечание. clang имеет предупреждение о перемещении.