Rule A5-0-4 (required, implementation, automated)
Pointer arithmetic shall not be used with pointers to non-final classes.
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. Note: This also applies to the subscripting operator as E1[E2] is defined in terms of pointer arithmetic as *((E1)+(E2)).
Example
// $Id: A5-0-4.cpp 309849 2018-03-02 09:36:31Z christof.meerwald $
#include <algorithm>
#include <array>
#include <cstdint>
#include <cstdlib>
#include <memory>
#include <vector>
class Base
{
public:
virtual ~Base() noexcept = 0;
virtual void Do() = 0;
};
class Derived1 final : public Base
{
public:
void Do() final
{
// ...
}
private:
std::int32_t m_value { 0 };
};
class Derived2 final : public Base
{
public:
void Do() final
{
// ...
}
private:
std::string m_value { };
};
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();
}
}
void Foo(const std::vector<std::unique_ptr<Base>> &v)
{
// Compliant: uses std::unique_ptr for polymorphic objects
std::for_each(v.begin(), v.end(),
[] (const std::unique_ptr<Base> &ptr) {
ptr->Do();
});
}
void DoOpt(Base *obj)
{
if (obj != nullptr)
{
obj->Do();
}
}
void Bar()
{
std::array<Derived1, 2> arr1;
Base *base1 { arr1.data() };
Foo(base1, arr1.size());
DoOpt(&arr1[1]);
DoOpt(&base1[1]);
// Compliant: pointer arithmetic on final class
// Non-Compliant: pointer arithmetic on base class
std::array<Derived2, 2> arr2;
Base *base2 { arr2.data() };
Foo(base2, arr2.size());
DoOpt(arr2.data() + 1); // Compliant: pointer arithmetic on final class
DoOpt(base2 + 1);// Non-Compliant: pointer arithmetic on base class
std::vector<std::unique_ptr<Base>> v;
v.push_back(std::make_unique<Derived1>());
v.push_back(std::make_unique<Derived2>());
Foo(v);
}
See also
SEI CERT C++ Coding Standard [10]: CTR56-CPP: Do not use pointer arithmetic on polymorphic objects. JSF December 2005 [8]: AV Rule 96: Arrays shall not be treated polymorphically. C++ Core Guidelines [11]: T.82: Do not mix hierarchies and arrays.