Take the 2-minute tour ×

class A { public: int a;};

class B: public A {
    int c; 
    int d;

int main() {

    A* pA = new B[10];
    B* pB = new B[10];

    printf("\n%d", pA->a);
    printf("\n%d", pA->a);  // prints junk value

    printf("\n\n%d", pB->a);
    printf("\n%d", pB->a);
    return 0;

The second printf prints a junk value.

It should figure that it is pointing to an object of type B and increment by the sizof(B).

Why does that not happen?

share|improve this question
Arrays of polymorphic objects is always a red flag. I've never needed to do it in production code and it is very error prone, so I would almost universally say don't do it. An array of pointers to polymorphic objects is fine though. –  deft_code May 20 '10 at 0:47

7 Answers 7

up vote 7 down vote accepted

It can only know that at runtime. Imagine it slightly changed

A* a;
  a = new A[10];
  a = new B[10];

But that's not going to happen. C++ puts emphasize in speed, but this would basically make it into a language that ensures safety of operations. There is Java, C# and others that already solve this.

Kernel and device driver developers don't want a clever language runtime. They just want to have things run fast.

Have a look at Common undefined behavior in C++ question for all the things that will need to get "fixed" along. It won't be C++ anymore!

share|improve this answer
It's not purely about speed either -- if I'm writing (for example) an arbitrary looking set of bits to create a structure for an MMU, things will break if the run-time suddenly decides react on the assumption that the bit-pattern I've written means the memory really contains some other type than what I've said it does. –  Jerry Coffin May 19 '10 at 18:55
@Jerry yes that in addition. Good point. –  Johannes Schaub - litb May 19 '10 at 18:58
Whilst what you say is true about runtime behaviour, the example in the OP could have been caught at compile time if the type returned by new[] wasn't a pointer to an object, but a pointer to an array of objects. The same goes for the compiler tracking use of delete[] on pointers to arrays. Both are completely checkable at compile time, if you are willing to trade away backwards compatibility with C's degrading of arrays to pointers. –  Pete Kirkham May 19 '10 at 19:18
@Pete Kirkham: I agree, but that would only be possible with arrays of compile-time size. –  AndreyT May 19 '10 at 20:18
"if you are willing to trade away backwards compatibility with C's degrading of arrays to pointers" - and introduce a variable-length-array type. Which is doable (C99 did it, to some extent), but isn't as straightforward as you'd hope, since it requires special-casing various parts of the standard. For example, "sizeof is evaluated at compile time (except for variable-length arrays)". –  Steve Jessop May 19 '10 at 20:22

No it shouldn't. The declared type of pA is A*, so it is incremented by sizeof(A), which leaves it pointing to the middle of the first B in the array.

share|improve this answer

The reason it's fragile is that you're side-stepping everything it does to try to keep you safe. Until you're sufficiently experienced to know why these problems are arising, and how to avoid them, you should:

  1. Forget that printf exists. Use std::cout instead.
  2. Forget that new exists. Use std::vector instead.

You should probably also read the C++ FAQ, and pay close attention to the part that says something to the effect that: "Even if an X is a Y, an array of X is not an array of Y."

Edit: As to why you're seeing the behavior you are, it's pretty simple: pointer arithmetic is defined in terms of the static type, not the dynamic type. That means it's based entirely on the type of pointee you defined for the pointer, NOT what it's pointing at. If you say it's pointing at an A, but then point it at a B, the arithmetic will still be done as if it was pointing at an A as you said it would.

share|improve this answer
Using a vector instead of an array would prevent him from doing the invalid cast, but using output streams wouldn't be any safer than printf here. Using standard library is a components is a compliment, not a substitute, for understanding the basics of the language. –  Alan May 19 '10 at 18:57
@Alan: while it's true that printf didn't cause this particular problem, it's still rarely a good thing to use in C++. I don't advocate anything as a substitute for understanding, but I do advocate following reasonable rules until you do understand well enough to know when to break them. –  Jerry Coffin May 19 '10 at 19:04
in response to your part 2 -> why doesn't there exist an auto_ptr<> style RAII idiom where you simply have { new_ptr<Type> obj; Type* t1 = obj.get(); } I really don't want vector semantics for a single pointer value. –  Chris Kaminski Jun 2 '10 at 18:24
@Chris: there are a couple of things like that (including auto_ptr, unique_ptr, and shared_ptr). The number stems (mostly) from different ideas of what such a thing should really do. Most of the time, you're better off just using an object directly though. –  Jerry Coffin Jun 2 '10 at 18:56
what I mean is that want something like this: new_ptr<Type> obj; instead of auto_ptr<Type> ptr(new Type);. I don't EVER want to use operator new directly. –  Chris Kaminski Jun 3 '10 at 2:20

Pointer a points to an object that has static type A and dynamic type B. Pointer arithmetic in C++ works in terms of static type. So, from the point of view of pointer arithmetic, a points to an object of type A.

share|improve this answer

the objects have no record of what or how large they are, it's just allocated memory. The only way the compiler knows how to treat the object at the pointer memory, is by looking at the pointer type. So based on pointer A*, it will only assume an object of sizeof(A).

share|improve this answer

For reasons of compatibility with C arrays degrade to pointers. The type of B[10] may degrade to B*, and inheritance means that the assignment of a pointer to B to a variable of type A* is valid.

You then increment the value of this pointer, which adds the size of A to its address.

However, your assumption that incrementing a pointer is a valid operation if the pointer is not pointing to an array of elements of the type of the pointer is not correct.

If you try and combine the parts of C++ which are there so it behaves like C with the more strongly typed OO features, the looser typing in the C parts defeats the stronger typing in the C++ parts. It's best to keep them separate, or at least document the expected behaviours.

share|improve this answer

You're incremeneting the variable a, which is a locally declared pointer of A objects. That's the same as saying a=a+sizeof(A).

Since sizeof(B)>sizeof(A), you end up pointing into the middle of the first object. When C++ then adds the appropriate offset, it'll end up reading the c field of the first B object. That happens to be unitialized memory, containing "junk".

share|improve this answer
i think you mean sizeof(B) > sizeof(A) –  Marlon May 19 '10 at 19:21
@Marlon: Yes, of course. Thanks for noticing. –  Michael Madsen May 19 '10 at 19:49

Your Answer


