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;
}
estimate
call is guaranteed to be called first. Which means the exception will be thrown before the actual null-pointer dereference happens. Is the code still UB even when the code causing the UB does not execute? That's an interesting question... :) – Tergummodel
is an argument toestimate
, how do you want the function to be called before the argument is accessed ? Or what do you mean with "accessed" ? – Reginamodel
is ok, it a validshared_ptr
, only dereferencing it is not ok because it does not point to a valid pointee – Rileyrilievomodel
as if it would be a raw pointer is also a tiny bit confusing – Rileyrilievo->
is evaluated anyway godbolt.org/z/n13P18M3G. Also, using raw pointers (which should basically be the same issue here) gives the same diagnosis godbolt.org/z/TPT7Y89cG – Permittivitymodel
was a raw pointer. edit: only now I see the answer. It does make a (tiny) difference – Rileyrilievomodel->set()
were a virtual function call, there's some dereferencing work to get to the actual function pointer. Of course, overlapping that work with setting up the args would still be possible per the as-if rule in cases where arg setup didn't maybe throw, even if the standard did define that args were evaluated first. So the actual wording in the standard seems somewhat backwards in making this UB and unsafe on paper. Perhaps they were thinking of cases where the postfix-expression is non-trivial, likefptr[++i]( 4*i )
to iterate through an array of function pointers. – Stores