Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does the following code invoke undefined behaviour?

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).

like image 699
wakjah Avatar asked Dec 17 '14 17:12

wakjah


1 Answers

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.

like image 174
Jason R Avatar answered Sep 22 '22 03:09

Jason R