Search code examples
c++structlanguage-lawyersequence-points

Is the `this` argument evaluated before or after other member function arguments?


In the following code a member function set() is called on a model, which is a null pointer. This would be undefined behavior. However, the parameter of the member function is a result of another function call that checks whether the model is a null pointer and throws in that case. Is it guaranteed that estimate() will always be called before the model is accessed or is it still Undefined Behaviour (UB)?

#include <iostream>
#include <memory>
#include <vector>


struct Model
{
    void set(int x)
    {
        v.resize(x);
    }

    std::vector<double> v;
};


int estimate(std::shared_ptr<Model> m)
{
    return m ? 3 : throw std::runtime_error("Model is not set");
}

int main()
{
    try
    {
        std::shared_ptr<Model> model; // null pointer here
        model->set(estimate(model));
    }
    catch (const std::runtime_error& e)
    {
        std::cout << e.what();
    }

    return 0;
}

Solution

  • This is still undefined behavior (UB) as per expr.compound:

    The postfix-expression is sequenced before each expression in the expression-list and any default argument. The initialization of a parameter, including every associated value computation and side effect, is indeterminately sequenced with respect to that of any other parameter.

    (emphasis mine)

    This means that the postfix expression model->set is sequenced before the expression estimate(model) in the expression-list. And since model is null pointer, the precondition of std::shared_ptr::operator-> is violated and hence this leads to UB.