0

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.

Barry
  • 286,269
  • 29
  • 621
  • 977
BenBaron
  • 3
  • 1
  • 2
    Wow, this sounds really, really fishy. What are you actually trying to do? This is most likely an XY problem. – Baum mit Augen Nov 30 '14 at 19:11
  • It will work with shorts, but not doubles. Casting a double to an int is a lossy conversion. – Robert Harvey Nov 30 '14 at 19:11
  • Let's just say for a moment that you've managed to put some values that are actually `double*` into this map? How would you later find out which key has which value ? And another thing, how can you be sure what will be the [size](http://stackoverflow.com/a/589684/1941161) of e.g int ? – Scis Nov 30 '14 at 19:25
  • Just a simple remark : angle brackets `<>` are normaly part of code and you can use backtics (\`) to delimit it. – Serge Ballesta Nov 30 '14 at 19:31
  • I need to read some values depending on user input which is read in as a wstring, thus I am using the map to match the wstring to the relevant value via the pointer. I am reading your comments as if I am actually trying to store the values in the map. That this would work with smaller data types bytes but not with larger ones is clear to me. I need to understand what is actually done internally in terms of reading out of the map while casting the short* back to int*. As far as I understand it, the size of datatypes is depending on the hardware where the compiler runs on, so my hardware. – BenBaron Nov 30 '14 at 20:01

2 Answers2

3

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;
Barry
  • 286,269
  • 29
  • 621
  • 977
  • @LightnessRacesinOrbit Wasn't sure if the pointers were a requirement. – Barry Nov 30 '14 at 19:53
  • Thanks Barry, always appreciate new input, although I didn't want to expand into other libraries apart from standard until I really fully understand the basics. But will definitely look into it. – BenBaron Nov 30 '14 at 21:08
0

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
Serge Ballesta
  • 143,923
  • 11
  • 122
  • 252
  • Thanks...that's what I ultimately wanted to know, as I simply wasn't sure if it wasn't by coincidence that it worked on my machine. The reason I need something like this is, that I am interfacing with another application. It's SDK (and the library) define a struct with a lot of ints (and little shorts and doubles) I'd like to read from it depending from user request (input by string). Thus, I thought it would be best to do it like this...store the pointers and dereference as needed. As the shorts and doubles are really not many, I'd do a small if/else combination to find out which cast to use. – BenBaron Nov 30 '14 at 21:18