Если вы используете std::shared_ptr<foo>&&
в качестве типа параметра (или любого ссылочного типа), тогда проблем не будет, потому что вызов std::move
фактически не изменяет объект в любом случае. Не имеет значения, выполняется ли он первым.
До C ++ 17 вариант по значению небезопасен. Не существует правила секвенирования, которое гарантировало бы, что выражение, называющее функцию, будет оценено перед инициализацией параметров функции. Таким образом, построение перемещения параметра функции может произойти до того, как p->bar
будет оценено.
Начиная с C ++ 17, вычисление значения и все побочные эффекты постфиксного выражения, именующего функцию, секвенируются до вычисления значения и побочные эффекты всех выражений в аргументах вызова, что подразумевает, что конструктор параметра функции секвенируется после вычисления p->bar
. См. [expr.call] / 5 . Поэтому потенциально проблематичный c operator->
вызов на p
происходит первым, до создания перемещения, что делает код безопасным.
Те же утверждения сохраняются, если вы замените std::shared_ptr
на std::unique_ptr
.