Я хотел бы сделать что-то вроде этого
#include <iostream>
#include <memory>
struct Foo {};
using FooPtr = std::unique_ptr<Foo>;
FooPtr makeFoo() { return FooPtr(new Foo()); }
struct Baz
{
Baz(FooPtr foo) : Baz(std::move(foo), bar(foo)) {}
Baz(FooPtr foo, int something) : _foo{ std::move(foo) }, _something{ something } {}
private:
FooPtr _foo;
int _something;
static int bar(const FooPtr & ptr)
{
std::cout << "bar!" << std::endl;
return 42;
}
};
int main() {
Baz baz(makeFoo());
return 0;
}
Мой вопрос: порядок вычисления аргумента функции не определен, поэтому безопасно передавать значение, из которого будет перемещен один аргумент, и результат вызова другой функции с тот же экземпляр, передается как ссылка на const, как другой аргумент?
Я думаю, что вопрос сводится к тому, когда именно выполняется фактическая операция перемещения, момент, который мне не совсем ясен (особенно когда речь идет о включенной оптимизации).
Фактическое «перемещение» не произойдет, пока конструктор перемещения std::unique_ptr<Foo>
выполняется (все std::move()
делает бросил const FooPtr &
значение в FooPtr &&
Rvalue ссылка). Это не произойдет, пока два аргумента Baz
вызывается конструктор, которому вы делегируете Чтобы это произошло, все аргументы этого конструктора должны быть оценены в первую очередь. Поэтому любое использование foo
объект в оценке этих аргументов произойдет до фактического «движения» unique_ptr
пример.
Поскольку вы передаете FooPtr
(a.k.a std::unique_ptr<Foo>
по значению и std::unique_ptr
только для перемещения, это вызовет конструкцию перемещения при оценке первого аргумента в конструкторе с двумя аргументами. Поскольку порядок оценки аргументов не определен, это перемещение может произойти или не произойти до оценки второго аргумента. Поэтому поведение вашего примера является неопределенные.
std::move
это не операция, это приведение к r-значению. Операция перемещения будет происходить внутри другого Baz
конструктор. В результате то, что вы делаете, должно работать.
Скотт Мейерс упомянул аналогичный ТАК вопрос в своем посте Должны ли типы только для перемещения передаваться по значению?. Кажется, что нет однозначного ответа, должны ли они быть переданы по значению или нет, но это может привести к неопределенному поведению, и в вашем случае это тоже так.