AUTOSAR rule A5-0-4 states
Pointer arithmetic shall not be used with pointers to non-final classes.
It provides the following rationale:
Pointer arithmetic is only well defined if the pointed-to type of the pointer equals the element type of the array it points into, otherwise the behavior is undefined. This property can only be guaranteed if the pointer operand is a pointer to non-class type or a pointer to final class type.
It then gives some examples of compliance and non-compliance. One of the non-compliances has me puzzled:
void Foo(Base *start, size_t len)
{
// Non-Compliant: pointer arithmetic on non-final pointer type
for (Base *iter = start; iter != start + len; ++iter)
{
iter->Do();
}
}
However unlikely it is that anyone would use a plain C-array to store polymorphic pointers, it's in the very fabric of the C++ language.
So my gut feeling is that there is nothing wrong with the above code.
Perhaps I am mistaken in this belief. Or perhaps I am completely missing the point that this AUTOSAR rule is trying to convey to the reader.
Can someone explain it better than the AUTOSAR document does?
See also AUTOSAR rule A5-0-4, which gives the full code used in the example.
I suspect you're missing the point. Consider something like this:
This has undefined behavior.
Fooexpects to receive the address of the beginning of an array ofBase. But we're passing a pointer toDerivedinstead of a pointer toBase. SinceFoo"thinks" it's manipulating pointers to base, when its loop does++iter, it's going to increment the address bysizeof(Base).As we've defined it, however, a
Derivedis almost certainly larger than aBase. After the incrementiteralmost certainly won't point to the secondDerivedobject, and when we try to callDoon that pointer, things will go sideways (no guarantee, but in a typical implementation, it'll end up trying to usedata[0].yas a vtable pointer to find the address ofDo).With the code precisely as it stands now, a compiler with decent optimization can probably cover up the problem. Since
Basehas a pure virtual, that can't be instantiated. There's only one class in the program derived fromBase, so it can conclude that anytime it's dealing withBaseobjects via a pointer (or reference) they must really be instances ofDerived, and act accordingly.To be sure of seeing the problem, we sort of need to have two derived classes, preferably of different sizes, and each with its own definition of
Do, so the compiler can't statically determine that there's only one possible type involved.When I attempt to compile/run this, I get:
So in this case, "goes sideways" translates to a segmentation fault (but you can't entire count on that as the only possible result).
Execution on Godbolt.org gives a similar result.