Home > Net >  Accessing a pointer to a derived class when it is not created
Accessing a pointer to a derived class when it is not created

Time:11-19

Why referring to a pointer to a derived class that has not yet been created is valid, but not undefined behavior. godbolt.org


#include <iostream>

struct A{
    int a;
     void foo() {
        std::cout << "A = " << a << std::endl;
     }
};

struct B : public A{
    int b;
    void foo() {
        std::cout << "B = " << b << std::endl;
    }
};


int main() {
    A *a = new A();
    B *b = static_cast<B*>(a);

    a->foo(); // cout A = 0
    b->foo(); // cout B = 0
    
    b->b = 333;
    
    b->foo(); // cout B = 333
    a->foo(); // cout A = 0
}

Should a pointer to a derived class be undefined?

CodePudding user response:

static_casting a pointer to a pointer-to-derived-class when the pointed-to object isn't actually a base class subobject of an object of the derived type, as you are doing with the cast in B *b = static_cast<B*>(a);, does have undefined behavior.

Undefined behavior does not mean that you are guaranteed to get an error or unintended behavior. Undefined behavior does however mean that you won't have any guarantee for the intended behavior either.

CodePudding user response:

Compile with -O3 -Werror -Wall to get the following message from gcc:

<source>: In function 'int main()':
<source>:25:8: error: array subscript 'B[0]' is partly outside array bounds of 'unsigned char [4]' [-Werror=array-bounds]
   25 |     b->b = 333;
      |     ~~~^
<source>:19:18: note: object of size 4 allocated by 'operator new'
   19 |     A *a = new A();
      |                  ^
cc1plus: all warnings being treated as errors

The message is somewhat funny, becuase it leaks some gcc implementation details by mentioning a unsigned char [4] when there is none. However, if you consider what is wrong in your code, the message nails it....

In memory, a B object looks like this (very simplified):

  A 
  B

It has an A subobject and after that comes the B members. Now it happens that A is of size 4 (could be different but thats what it is with gcc).

When you write b->b. Then b points to an A (not to ba B), but you pretend that it does point to a B. Hence when the compiler tries to apply the offset to the pointer to reach the member, this offset is larger than the size of the object. The compiler realizes that something cannot be right.


However, this is error message nothing more than an interesting curiosity. The compiler is not required to diagnose your mistake because your code has undefined behavior.

When your code has undefined behavior, anything can happen. The worst case is that the code appears to be fine and work as expected.

Why does your code compile and work ok? It does not. b does not point to a B. Your code could print "Hello World" to the console as well, it could erase your hard drive or really anything could happen. Only if your code has no undefined behavior there is a guarantee what your program will do.

  •  Tags:  
  • c
  • Related