我想做这样的事情
#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,作为另一个参数?
我认为这个问题可以归结为实际移动操作的执行时间,我不完全清楚(特别是在开启优化时)。
答案 0 :(得分:9)
实际&#34;移动&#34;在执行std::unique_ptr<Foo>
的移动构造函数之前不会发生(所有std::move()
都会将const FooPtr &
rvalue转换为FooPtr &&
右值引用。在您调用的双参数Baz
构造函数被调用之前,这种情况不会发生。为了使其发生,必须首先评估该构造函数的所有参数。因此,foo
对象在评估这些参数时的任何使用都将在实际的&#34;运动之前发生。 unique_ptr
个实例。
由于您传递的是FooPtr
(又名std::unique_ptr<Foo>
的值,std::unique_ptr
是仅移动的,因此在评估双参数的第一个参数时会触发移动构造构造函数。由于参数的评估顺序未指定,在评估第二个参数之前可能会或可能不会发生该移动。因此,示例的行为未指定。
答案 1 :(得分:4)
std::move
不是一个操作,它是对r值引用的强制转换。移动操作将在另一个Baz
构造函数内部发生。因此,您正在做的事情应该有效。
答案 2 :(得分:4)
Scott Meyers在帖子similar SO question中提到Should move-only types ever be passed by value?。似乎没有确定的答案是否应该通过价值传递,但这样做显然会导致一种不明确的行为,在你的情况下它也会这样做。