Search code examples
c++order-of-execution

Will this C++ code always work as I expect, or is the execution order not guaranteed?


OK, I have some code that seems to work but I'm not sure it will always work. I'm moving a unique_ptr into a stl map using one of the members of the class as the map key, but I'm not sure whether the move might invalidate the pointer in some situations.

The code is along these lines:

struct a
{
    std::string s;
};
std::map<std::string, std::unique_ptr<a>> m;
std::unique_ptr<a> p = std::make_unique<a>();

// some code that does stuff

m[p->s] = std::move(p);

So this currently seems works but it seems to me it might be possible for p to become invalid before the string is used as the map key, and that would lead to a memory exception. Obviously I could create a temporary string before the move, or I could assign via an iterator, but I'd prefer not to if it isn't necessary.


Solution

  • This code has well-defined behaviour.

    In C++17, std::move(p) will be evaluated before m[p->s]. Before C++17, std::move(p) could be evaluated either before or after m[p->s]. However, this doesn't matter because std::move(p) does not modify p. It is only the assignment that actually causes p to be moved-from.

    The assignment operator that is called has the signature

    unique_ptr& operator=(unique_ptr&& other);
    

    and is called as if by

    m[p->s].operator=(std::move(p));
    

    This means that the modification of p is guaranteed to not take place until the body of operator= is entered (the initialization of the other parameter is merely a reference binding). And certainly the body of operator= cannot be entered until the object expression m[p->s] is evaluated.

    So your code is well-defined in all versions of C++.