Let's say I have a class Derived
which derives from class Base
whereas sizeof(Derived) > sizeof(Base)
. Now, if one allocates an array of Derived
like this:
Base * myArray = new Derived[42];
and then attempts to access the n
-th object using
doSomethingWithBase(myArray[n]);
Then this is might likely (but not always) cause undefined behaviour due to accessing Base
from an invalid location.
What is the correct term for such an programming error? Should it be considered a case of object slicing?
This is not object slicing in any way.
Object slicing is perfectly well defined by the C++ standard. It may be a violation of object-oriented design principles or whatever, but it is not a violation of C++ rules.
This code violates 5.7 [expr.add] paragraph 7:
Array subscript operator is defined to be equivalent to pointer arithmetic, 5.2.1 [expr.sub] paragraph 1:
It is not slicing at all, rather it is undefined behavior because you are accessing a
Derived
object where none exists (unless you get lucky and the sizes line up, in which case it is still UB but might do something useful anyway).It's a simple case of failed pointer arithmetic.
This is not object slicing.
As noted, indexing
myArray
does not cause object slicing, but results in undefined behavior caused by indexing into an array ofDerived
as if it were an array ofBase
.A kind of "array decay bug".
The bug introduced at the assignment of
new Derived[42]
tomyArray
may be a variation of an array decay bug.In a true instance of this type of bug, there is an actual array:
The problem is introduced because an array of
Derived
decays into a pointer toDerived
with value equal to the address of its first element. The decay allows the pointer assignment to work properly. This decay behavior is inherited from C, which was a language design feature to allow arrays to be "passed by reference".This leads us to the even worse incarnation of this bug. This feature gives C and C++ semantics for arrays syntax that turn array function arguments into aliases for pointer arguments.
However,
new[]
is actually an overloaded operator that returns a pointer to the beginning of the allocated array object. So it is not a true instance of array decay (even though the array allocator is used). However, the bug symptoms are the same, and the intention ofnew[]
is to get an array ofDerived
.Detecting and avoiding the bug.
Use a smart pointer.
This kind of problem can be avoided by using a smart pointer object instead of managing a raw pointer. For example, the analogous coding error with
unique_ptr
would look like:This would yield a compile time error, because
unique_ptr
s constructor isexplicit
Use a container, and maybe
std::reference
.Alternatively, you could avoid using
new[]
, and usestd::vector<Derived>
. Then, you would have forced yourself to design a different solution for sending this array to framework code that is onlyBase
aware. Possibly, a template function.Or, by using
std::reference_wrapper<Base>
.This is not a case of slicing, although it is very similar. Slicing is well defined. This is simply undefined behaviour (always, not just likely) due to illegal pointer arithmetic.