0

I have defined a member var of a derived class to be a reference to a member var of the base class. I am doing this because in the derived class, the name of the reference is more meaningful than the name of the original variable in the base class.

Now I am creating a buffer of char, large enough to contain an object of the derived class. I define a pointer to the derived class, and using a static_cast, point it to the buffer.

If a member function of the derived class dereferences the base class member var using its original name as defined in the base class, there is no problem.

But if it is dereferenced using the name of the reference, I get a memory access violation.

  1. Why the different behavior?
  2. How can I achieve what I am trying to do, which is to refer to the variable by a different name in the derived class?

    class B {
    public:
        int x;
        B () : x(10) {}
    };
    
    class D : public B {
    public:
        int &y{ x };
        // No problem here:
        inline bool IsXTen () { return ((x == 10) ? true : false); }
        // Memory Access Violation occurs here:
        inline bool IsYTen () { return ((y == 10) ? true : false); }
    };
    
    int main(int argc, char* argv[])
    {
        char buf[sizeof (class D)] = { 0 };
        void *pVoid = buf;
        class D *pd = static_cast<class D*>(pVoid);
    
        if (pd->IsXTen ()) {
            return 1;
        }
    
        if (pd->IsYTen ()) {
            return 2;
        }
    
        return 0;
    }
    
sifferman
  • 2,955
  • 2
  • 27
  • 37
  • 1
    Why do you static_cast this? You've got a buffer big enough for a `D` but __there is no `D` in it__. – tkausl Apr 15 '18 at 14:02
  • 4
    The `static_cast` does not construct a `D`. As such, the members `x` and `y` are not guaranteed to be initialised as specified in the respective class definitions. Accessing either of them therefore causes undefined behaviour. – Peter Apr 15 '18 at 14:04
  • That's a very odd way to do things. Why not just `new D();` instead of all those hoops? Also, `class D * pd` -- the `class` is redundant. You probably should even use `new` at all. – Clearer Apr 15 '18 at 14:05
  • @Clearer "If you don't want to call the constructor (you do), use `new D;`" `new D;` calls the constructor. – tkausl Apr 15 '18 at 14:07
  • @tkausl I was told it didn't. I never used it. Not calling the constructor is like not having breaks in your car. – Clearer Apr 15 '18 at 14:08
  • You might want to look into "placement new". – 001 Apr 15 '18 at 14:10
  • The buffer already exists, and contains an object of class D. I want to cast a pointer to this object so I can call D member functions on the data. This is in an embedded system where dynamic memory allocation (i.e. new & delete) is not permitted. – sifferman Apr 15 '18 at 14:11
  • @sifferman "and contains an object of class D" In the code you posted there is no D. "This is in an embedded system where dynamic memory allocation (i.e. new & delete) is not permitted." Placement-new doesn't allocate memory. – tkausl Apr 15 '18 at 14:12
  • @tkausl You're right - my example doesn't show the buffer being filled with a D object. I was trying to keep the example short. – sifferman Apr 15 '18 at 14:14
  • @sifferman The analogy is that you created a cardboard box the size of a car, and are attempting to start the box and drive it. – PaulMcKenzie Apr 15 '18 at 14:15
  • @sifferman *my example doesn't show the buffer being filled with a D object.* -- How many more lines of code would that have taken to show the buffer being filled? – PaulMcKenzie Apr 15 '18 at 14:16
  • Sounds like `placement new` may do the trick. Why haven't I heard of this before? – sifferman Apr 15 '18 at 14:18
  • @sifferman -- [Uses of placement-new](https://stackoverflow.com/questions/222557/what-uses-are-there-for-placement-new). The goal is to actually construct the object -- your attempt constructed no object, thus you can't do "object stuff" on it, such as calling member functions. Placement-new allows object construction in a memory area you have designated. – PaulMcKenzie Apr 15 '18 at 14:23
  • Wait a second... you've purposefully created a code example which you know doesn't work because it invokes undefined behaviour and are expecting answers about the reason of a crash for code you don't show? – Christian Hackl Apr 15 '18 at 15:55
  • In fact, the char buffer in the above code is being initialized to all zeros. Therefore for purposes of the example I assumed the `int x` was being initialized to `0`, which testing has borne out. In my actual application, the memory is filled by another process. I further assumed the `int&y{x}` would cause `y` to behave as an alias for `x`, because virtually every explanation of references I have read leads me to believe that's how they should be regarded. But in fact a memory access violation occurs. `placement new` should work as long as the constructor doesn't overwrite the data in memory. – sifferman Apr 15 '18 at 16:46
  • Why array and placement new at all? `int main(){ D d; /*...*/ }` is all you need to create a variable on the stack... Be aware that if you still use placement new like this, you need to *explicitly* call the destructor, too! – Aconcagua Apr 16 '18 at 06:51
  • Side note: the result of *any* comparison in C++ has already type bool! So by `return condition ? true : false;`, you produce redundant/obsolete code which is bad style anyway. Just do `return condition;` instead... Parentheses around return values are bad style, too, and in some cases even can change behaviour: `int x = 0; return (x);` will return x as *reference*! – Aconcagua Apr 16 '18 at 06:54

2 Answers2

1

The reference is likely stored as a pointer in the object's memory layout (see Why do references occupy memory when member of a class? ). You are not calling the constructor that initialises that reference/pointer so using it is undefined.

Janne Husberg
  • 294
  • 1
  • 9
  • Thank you for your answer. I understand now why it doesn't work, but this doesn't solve my problem. – sifferman Apr 16 '18 at 17:43
  • As the issue is that the reference is not initialised, your only option is to initialise the reference or not use a reference. – Janne Husberg Apr 16 '18 at 19:17
  • If you want to initialise the reference, create a function that does that or look into how to [call a constructor without zero-initialising default fields](https://stackoverflow.com/questions/4167662/can-i-prevent-zero-initialization-of-the-elements-in-an-array-data-member-in-a-n). – Janne Husberg Apr 16 '18 at 19:18
  • If you do not need the reference, create a getter. – Janne Husberg Apr 16 '18 at 19:18
1

As mentioned in the comments, the way you are doing it does not construct the object. Use "placement new" in this case to properly construct it:

char buf[sizeof (class D)] = { 0 };

// Class not initialized, constructors not called
// class D *pd = static_cast<class D*>(pVoid);

// Object is properly initialized
class D *pd = new (buf) D;
001
  • 13,291
  • 5
  • 35
  • 66
  • Thank you for your answer. It turns out `placement new` won't solve my problem because constructing the object causes the buffer that contains the data to be overwritten. I was trying to create an object based on data that already existed in a buffer, without copying that data. – sifferman Apr 16 '18 at 17:40