I would like to do something like this
#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;
}
My question is: the order of function argument evaluation is unspecified, so is it safe to pass a value that will be moved from in one argument, and the result of calling another function with the same instance, passed as reference-to-const, as the other argument?
I think the question boils down to when, precisely, the actual move operation is performed, a point on which I'm not entirely clear (especially when it comes to having optimization turned on).
The actual "moving" wouldn't occur until the move constructor of std::unique_ptr<Foo>
is executed (all std::move()
does is cast the const FooPtr &
rvalue into a FooPtr &&
rvalue reference). This wouldn't occur until the two-argument Baz
constructor that you're delegating to is invoked. In order for that to occur, all of the arguments to that constructor have to be evaluated first. Therefore, any use of the foo
object in evaluating those arguments will happen before the actual "movement" of the unique_ptr
instance.
Since you are passing the FooPtr
(a.k.a std::unique_ptr<Foo>
by value, and std::unique_ptr
is move-only, that will trigger a move construction when evaluating the first argument to the two-argument constructor. Since the order of evaluation of arguments is unspecified, that move may or may not occur before evaluation of the second argument. Therefore, the behavior of your example is unspecified.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With