BenBaron
BenBaron

Reputation: 3

casting short*/double* to int* and back and dereference

as I am quite new to C++ and still have to learn a lot, please bear with me and maybe some stupid questions:

Basically, I am declaring a map<wstring, int*>, as most of the variables I am going to dereference and use are ints (4 bytes). Unfortunately, there are rare ones being doubles (8 bytes) or shorts (2 bytes) and I don't have any influence on this. For the sake of simplicity and as I want to learn something I'd like to read all of the pointers into the same map. Here are my thoughts:

map[wstring] = (int*) short*;//or double*

Would the above work in terms of that only the beginning of the short's or double's memory address is stored in the map and not the memory's actual content?

As I know, which keys are different I would cast the pointers back to their type before dereferencing:

short = *((short*) map[wstring]); // or double = *((double*) map[wstring]);

From my point of limited knowledge this may work. I'd say that, although from the stored memory address there would normally be read 4 bytes, as this is what the map was declared for, now, by casting to short* or double*, I am saying that I'd like to read 2 or 8 bytes from the beginning of the stored address. In fact, it did work at least with shorts but I am not sure if this was just coincidence and I need to be sure.

Again, I am sorry if this is total nonsense and thanks in advance for mind enhancing answers.

Upvotes: 0

Views: 147

Answers (2)

Serge Ballesta
Serge Ballesta

Reputation: 148900

You can always cast a pointer to a pointer to a different type, even if you have to pass through a void pointer. But at dereferencing time you will get garbage since you will misinterprep a memory zone.

If you have some piece of magic to know what pointers are actually short * or double *, you sure can do it. Here is an example :

#include<iostream>

using namespace std;

int main()
{
    double b = 0.5;
    short h = 10;
    int i = 5;
    int *t[3] = { (int *) &b, (int *)&h, &i };
    cout << *((double *) (t[0])) << " " << *((short *) (t[1])) << " " << *(t[2]) << endl;
    return 0;
}

gives :

0.5 10 5

And my advices are :

  • do not use that unless you have a strong reason to do it
  • never use it in a real application

Upvotes: 0

Barry
Barry

Reputation: 302942

If what you want is to store a pointer to some arbitrary data, then maybe one of the simplest things to use is a tagged union like Boost.Variant:

typedef boost::variant<
    int*,
    double*,
    short*
> SomePtr;

std::map<wstring, SomePtr> m;

That way you can store any of the pointer types safely and use the various features that the variant type provides to get the value out (e.g. boost::apply_visitor()). Now I'm not sure if storing pointers is a requirement or not, but this works just as well if you use it as variant<int, double, short>.

Alternatively, if you don't want to use Boost, you can write your own version of this variant with a union and an index:

class Variant {
    union {
        int* iptr;
        double* dptr;
        short* sptr;
    };
    int which;

public:
    Variant(int* p): iptr(p), which(0) { }
    Variant(double* p): dptr(p), which(1) { }
    Variant(short* p): sptr(p), which(2) { }

    // example
    template <typename F>
    void visit(F f) {
        switch (which) {
            case 0: f(iptr); break;
            case 1: f(dptr); break;
            case 2: f(sptr); break;
        }
    }
};

std::map<wstring, Variant> m;

Upvotes: 3

Related Questions