简体   繁体   中英

C++ Create two variables with overlapping memory

I have two structs , Rect and Point . I cannot change their implementation, regrettably.

The definition of Rect is:

typedef struct Rect
{
    int x, y;
    int w, h;
} Rect;

The definition of Point is:

typedef struct Point
{
    int x, y;
} Point;

I would like to keep a single Rect, effectively, but keep the w / h members hidden.

I wondered if it was possible to create a Point object using the same address in memory such that the x / y memory is shared between each object?

I have tried using placement new , and it didn't seem to work, as well as reassigning the address, which obviously didn't work either.

Anyone have any ideas? I know this probably isn't the best practice, but it would be a neat trick and make things a lot simpler to work with.

hnefatl

You should hide your Rect inside your own class, providing the interface you need. Something like:

class MyRect
{
    private:
        Rect _rect;

    public:
        MyRect(const Rect& rect);

        int& x() { return _rect.x; }
        int& y() { return _rect.y; }
}

C++ has the concept of layout compatible. Your Point and Rect classes are layout-compatible as they have a common initial prefix, and they are standard-layout (or plain old data in C++03).

This means

Rect r = {1,2,3,4};
Point* p = &reinterpret_cast<Point*>(&r);

generates a Point pointer p that points to the x and y fields of the Rect r . Modifying the x and y fields of *p will modify the values in r , and modifying rx and ry will modify the values in *p . Well, sort of.

The downside is the concept of aliasing and strict aliasing. If you turn off strict aliasing in your compiler, it will lose some optimizations, but the above will work.

To get it to work with strict aliasing working you need to store both your Rect and your Point in a union:

union MyUnion {
  Rect r;
  Point p;
};
MyUnion u = Rect{1,2,3,4};

and now px and py refer to rx and ry in any context where "it is permitted to inspect the common initial part of any of them anywhere that a declaration of the complete type of the union is visible". So where MyUnion can be seen, you are safe -- but where it cannot be seen, the compiler is free to treat a pointer-to- Point modifying x as not being able to modify the pointer-to- Rect 's x . This is important for optimization purposes, as without it reordering unchanged sub expressions becomes next to impossible.

If you wanna hide w and h , maybe you can create an "ad hoc" Point based on Rect values and use this structure... then, if x and y can be different than originals you can set current values to original Rect variable:

Rect original_rect;

// ...

Point point;
point.x = original_rect.x;
point.y = original_rect.y;

// code that use Point instead of Rect
// ...

// Set current values to original variable
original_rect.x = point.x;
original_rect.y = point.y;

On the other hand, if you need to use Rect class and hide w and h at the same time... you cannot do it

Based on the comments and answers, it seems this is impossible. Oh well, would've been a nice trick with pointers!

I'll just keep the rect and not hide the w and h members.

Thanks to all who answered :)

hnefatl

PS The code I'm using is written in C, and I'm using C++ to interact with it. Sorry, forgot to mention that :/

PPS Thanks for the link explaining a union Joachim, I'd never got round to learning about them!

An option is to let the Rect derive from Point so that it inherits its members.

typedef struct Rect: struct Point
{
    int w, h;
} Rect;

and use pointers of the type you like when you want.

Another option is to keep the original types and use wild casts, like

struct Point* MyPseudoPointPtr= (struct Point*)&MyRect;

This will work with references too

struct Point& MyPseudoPoint= *(struct Point*)&MyRect;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM