C++ Question Handles, void* and casting

fred18

Addon Developer
Addon Developer
Donator
Joined
Feb 2, 2012
Messages
1,667
Reaction score
115
Points
78
Hi guys,

I've been working a bit in these days and I have the following doubt.

Let's say that I am making a project and that I also make the relevant APIs and SDK for others to use it.

Let's also say that I want to put Handles made by myself in it. Actually it is not the case but I am in the exact position of implementing this and I am willing to learn how to properly do it.

The thing I am working on is a linking system between vessels which will behave phisically like docking but with the commands and hierarchy of attachments.

So I have a std::vector holding the list of all the links in the sim which are processed at every frame.

The links are identified by a unique index, which never changes during runtime and that never duplicates.

So if I want to identify the link I can refer to its index, which means (to my eyes) that the index is the best candidate for a linkhandle here.

So I made the linkAPI.h which basically just contains
Code:
typedef void* LINKHANDLE;

and then when I pass the linkhandle in the process the handle gets casted back to integer to get the index.

The issue I am encountering is relevant to the void* pointer and to pointers in general... for example in a function if I try to use the static_cast it doesn't work:

Code:
bool LinkManager::ActivateLink(LINKHANDLE lh) {
	int index = static_cast <int>(lh);
...
...
return FALSE;
}

the compiler says that this conversion of type is not valid and my guess is that because void* is a pointer while int is not.

if I change it to
Code:
int* index = static_cast <int*>(lh);

then the conversion works, but I don't want a pointer to an integer, I want an integer to use so it seems not useful to me (even if I realize that pointers can work also this way if only I could get it...)

but to my surprise this works fine even though my feel is that it's not right:

Code:
bool LinkManager::ActivateLink(LINKHANDLE lh) {
	int index = (int)lh;
...
... 
return FALSE;
}

So... what's the proper way to do it?

thanks in advance to anyone! :cheers:
 
Why is the handle of type void pointer to start with? Just define it as integer and be done with it.

Besides this, there is nothing bad about using a C-style cast. It just tells the compiler to use the value as a different type.
 
The proper way is the way that it works without bugs. I would also recommend using an long or another value and not a pointer.

Especially because pointers are not type-safe as I had to experience a few weeks ago: sizeof(void*) is 4 on a 32-bit system, but 8 on a 64-bit system. It could really drive you mad, if you are expecting a 32 bit value there.
 
Why is the handle of type void pointer to start with? Just define it as integer and be done with it.
to be honest I gave a look at orbiterAPI.h and all the handles there are defined as typedef void*, so I used the same to see how it worked... I don't know if that is because the scope of the handle is to "hide" the real implementation behind a certain process.

Besides this, there is nothing bad about using a C-style cast. It just tells the compiler to use the value as a different type.

The proper way is the way that it works without bugs. I would also recommend using an long or another value and not a pointer.

"Safety" is the reason why I tried only with static_cast (AFAIK it's the safest way to cast). I'll define the handle as an integer anyway and I will sleep better because it's surely much safer

One question though: if I use something like "typdef int LINKHANDLE" then can I use the handle as an integer itself or shall I cast to an integer when I use it ?
 
One question though: if I use something like "typdef int LINKHANDLE" then can I use the handle as an integer itself or shall I cast to an integer when I use it ?


I would cast once at the beginning of a function and never use a LINKHANDLE then in any code where you are doing integer operations.


Simply for avoiding any possible mistake that might arise from assuming a LINKHANDLE is always an integer. Of course, it must be so, because otherwise, the initial cast will fail.



But more so, you can assert automatically if the initial cast is valid, while this would be impossible if you assume that the LINKHANDLE is an integer. For example, you could start counting your LINKHANDLE with 10000, so any integer case from it with less than 10000 would be invalid. Same with using prime number steps there other than 2. For example, if you use LINKHANDLE = 100000 + 7 * index - you can quickly check with a modulus, if the handle is not result of an illegal operation.
 
Honestly, if your object is already hidden inside a vector, and all you expose is its index, I don't quite see the point of using a handle architecture in the first place. The whole point of a handle is to pass objects around without granting access to them (well, not too obvious access, anyways), a goal that you can easily achieve safer by proper access methods.
The advantage of using handles is that code that receives a handle doesn't need to have access to the data structure containing the object, because it already has the object, but if your handle is an index used to retrieve the object, that advantage is gone and it must be assumed that providing proper access to everybody who needs it isn't a problem. So... just use the index. You can still typedef an int if you think that leads to clearer code, but passing an index as a handle has no benefit and unnecessarily makes your code more obtuse and unsafe.
 
Back
Top