Reputation: 721
So I was reading the article on Handle in C and realized that we implement handles as void pointers so "whatever" Object/data type we get we can cast the void pointer to that kind of Object/data and get its value. So I have basically two concerns :
1.If lets say in following example taken from Handle in C
typedef void* HANDLE;
int doSomething(HANDLE s, int a, int b) {
Something* something = reinterpret_cast<Something*>(s);
return something->doit(a, b);
}
If we pass the value to the function dosomething(21,2,2)
, does that mean the value HANDLE points to is 21, if yes how does any object when we type cast it to that object, will it be able to use it, like in this example, so in otherwords where does pointer to the object Something, something
, will store the value 21.
2.Secondly the link also says "So in your code you just pass HANDLE around as an opaque value" what does it actually mean? Why do we "pass handle around"? If someone can give more convincing example of handles that uses objects that will be great!
Upvotes: 2
Views: 6024
Reputation: 206607
If we pass the value to the function dosomething(21,2,2), does that mean the value HANDLE points to is 21,
No. It just means that value of the void*
is 21. If you treat 21 as the value of a pointer to an object of type Something
, it will most likely lead to undefined behavior.
2.Secondly the link also says "So in your code you just pass HANDLE around as an opaque value" what does it actually mean? Why do we "pass handle around"? If someone can give more convincing example of handles that uses objects that will be great!
A handle is opaque in the sense that you cannot see anything through it. If a handle is represented by a void*
, you can't see anything about the object since a void*
cannot be dereferenced. If a handle is represented by an int
(as an index to some array defined elsewhere in your code), you can't look at the value of the handle and make any sense of what the corresponding object represents.
The only way to make sense of a handle is to convert it a pointer or a reference using a method that is appropriate for the handle type.
In the case where a handle is represented by a void*
, the code you have posted illustrates how to extract a pointer to a concrete object and make sense of the object.
In the case where a handle is represented by an int
, you may see something along the lines of:
int doSomething(HANDLE s, int a, int b) {
// If the value of s is 3, something will be a reference
// to the fourth object in the array arrayOfSomethingObjects.
Something& something = arrayOfSomethingObjects[s];
return something.doit(a, b);
}
Upvotes: 1
Reputation: 4010
I didn't realize there was one defacto article on HANDLEs or a defacto way to implement them. They are usually a windows construct and can be implemented any way some developer from 1985 decided to implement them.
It really has as much meaning as "thingy", or rather "thingy that can be used to get a resource"
Do not get into the habit of creating your own "handle" and certainly do not try to mimic code idioms from 1985. Void pointers, reinterpret_casts, and HANDLE are all things that you should avoid at all costs if possible.
The only time you should have to deal with "HANDLE" is when using the Windows API in which case the documentation will tell you what to do with it.
In modern C++, if you want to pass objects around, use references, pointers, and smart pointers(including unique_ptr, shared_ptr, weak_ptr) and study up on which scenarios call for which.
Upvotes: 1
Reputation: 1670
1.: A handle is an identifier for an object. Since "21" is no object, but simply a number, your function call is invalid. Your code will only work if 's
' really points to a struct of type Something
. Simply spoken, a handle is nothing than a pointer is nothing than a memory address, thus "21" would be interpreted as a memory address and will crash your program if you try to write to it
2.: "Opaque value" means that no developer that uses your code can't take any assumptions about the inner structure of an object the handle identifies. This is an advantage over a pointer to a struct, where a developer can look at the structure and take some assumptions that will not be true anymore after you changed your code. "Pass around" simply means: assigning it and using it as a function call parameter, like in:
HANDLE s = CreateAnObject();
DoSomethingWithObject( s );
HANDLE t = s;
etc.
By the way: In real code, you should give handles to your objects different names, like EMPLOYEE_HANDLE, ORDER_HANDLE etc. A typical example of a handle are window handles in Windows. They identify windows, without giving you any information about how a "Window" memory structure in the operating system is built, therefore Microsoft was able to change this inner structure without the risk of breaking other developer's code with changes to the "Window" structure.
Upvotes: 5