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.
Foo
expects to receive the address of the beginning of an array ofBase
. But we're passing a pointer toDerived
instead 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
Derived
is almost certainly larger than aBase
. After the incrementiter
almost certainly won't point to the secondDerived
object, and when we try to callDo
on that pointer, things will go sideways (no guarantee, but in a typical implementation, it'll end up trying to usedata[0].y
as 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
Base
has 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 withBase
objects 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.