How closely does passing a void pointer in C++ imitate defining a method parameter as object
if you don't rightly now what that type will be at compile time?

- 2,699
- 3
- 25
- 42

- 8,461
- 33
- 112
- 197
-
IMO it doesn't _imitate_ very much. Point to have Object base class is to provide some shared behavior (ToString(), comparison, hashing). If it's a placeholder for _any type_ how this will help? Will you dynamic_cast to see which (base?) class you can use? – Adriano Repetti Dec 09 '14 at 14:56
-
Using void pointer in C++ is a code smell. I'd even call it an unbearable stench. – Fred Larson Dec 09 '14 at 15:03
-
Please edit your question with an example; this will help clarify. – Thomas Matthews Dec 09 '14 at 15:13
-
In C++, if you don't know the type, you'd use `template
`. Once you pass an actual argument, the compiler will then fill in `T` and check (still at compile time) if that makes sense. – MSalters Dec 09 '14 at 16:27
3 Answers
Let's get a few things straight that are getting missed in the other answers. All objects (except structs) in C# are passed as pointers. C# (and Java) hide the pointer syntax because of all the horrible things that can go wrong with it and since even the most seasoned C/C++ programmer with inadvertently shotgun the heap by pointer misuse, this is a very good thing.
void *
in C (and in C# - it exists if you turn on unsafe code) is a pointer to an address with absolutely no implication as to what that might be. Early in C there was neither void
nor void *
. If we wanted a function to return nothing, we didn't put in a return statement. It was still implicitly int
, but the value was unpredictable. Without void *
, we typically used char *
instead, but programmers didn't like that since it implied a pointer to characters or a string and an implication as to how to perform math on the pointer if sizeof(char) != 1
. With void *
there is no implication that you are pointing to any particular type at all and you the programmer knows best as to what is pointed to by a void *
(spoiler: most programmers don't).
So why would you use this? One typical use is to make use of a pointer as an opaque type in an API. For example:
extern void *get_device();
extern int is_device_active(void *device);
And this is all well and good - a consumer of this API doesn't know what the device is. Unfortunately, since anything is a void *
, this API lets you do some truly horrible things:
char *str = get_device(); /* wrong */
size_t len = strlen(str); /* doubly wrong */
int active = is_device_active("hi mom!"); /* can't express how wrong */
Yet, your compiler will allow this without a peep, which actually makes void *
not so useful in this case.
In C#, object
is another beast entirely. It has very strong implications as to what is at the pointer. It's either null
or it's an instance of a class that will let you do:
- Equals
- Finalize
- GetHashCode
- GetType
- MemberwiseClone
- ToString
All these are guaranteed to be there no matter what the actual object is. With void *
, you've got absolutely nothing except maybe a promise from API documentation.
The best use of void *
in C is malloc()
(and its variants) and free()
since they don't dictate what type they point to.
Also, if you're wondering how you actually present an opaque API in C, the typical pattern is:
/* device.h */
typedef struct t_device t_device;
extern t_device *get_device(); /* strongly typed now, but opaque */
extern int device_is_active(t_device *device);
/* device.c */
typedef struct t_device { /* this is private to the .c file */
int isActive; /* can't see it outside! Neener, neener! */
/* etc. */
} t_device;
t_device *get_device() { return make_device(); }
int device_is_active(t_device *device) { return device ? device->isActive : 0; }

- 48,267
- 11
- 78
- 120
-
what does the term `shotgun the heap` mean? that seems like some vernacular that would be good to know. +1 for the depth of answer as well. – wootscootinboogie Dec 09 '14 at 16:12
-
1Your heap is where all your memory is for dynamic allocation. To shotgun it is to write blindly into the middle of the heap and destroy allocated data that is in use or ruin the structure of the heap so later allocations or deallocations fail. Typical causes include (but are not limited to) using a deallocated pointed or writing past the end or beginning of an array. – plinth Dec 09 '14 at 16:19
-
"if `sizeof(char) != 1`". It is 1, by definition. The benefit of `void*` is exactly that you cannot do math on it since `sizeof(void)` is undefined. – MSalters Dec 09 '14 at 16:25
A pointer refers to a variable.
An instance of object
refers to a value.
This is a very key difference. Using a pointer you can mutate another variable (usually one that's not currently in scope). Using an object
instance you can only ever mutate a value, possibly one that another variable also reference, but that's still a key difference.
Because the pointer refers to a variable, mutations to the referred to variable variable will be observable through the pointer. The pointer is also capable of mutating that variable. An object
instance on the other hand is not tied to another variable. Even if the object it refers to is referred to by another variable, changes in that other variable won't be observable through the object
instance, and it also has no way of mutating the other variable.
There's also the fact that for an object
to reference a value type that value type needs to be boxed. This can have performance implications in that the values end up being copied, but also significant semantic differences. Mutations of the source variable won't be visible to the object
reference, while they would be had you used a void
pointer.

- 202,030
- 26
- 332
- 449
-
1If you mean C++, a pointer points to a variable, member of a variable, element in an array, heap-allocated object, function, or null. And I might be forgetting some options there, but "variable" is only one of many possibilities. – MSalters Dec 09 '14 at 16:23
-
@MSalters The result of dereferencing a pointer is a variable, not a value, as is the case when dealing with an object instance. That dereferenced result may be a variable that also exists elsewhere, or it may be a variable representing a value that *doesn't* have a variable representing it elsewhere, as would be the case if the value of the variable is a heap allocated object, an element in an array, etc. Does that phrasing satisfy you? – Servy Dec 09 '14 at 16:32
-
1Nope, see 3 [Basic concepts]/6. Variables have names and are introduced by definitions. The result of dereferencing a pointer is an lvalue (5.3.1 Unary operators). The C++ Standard is not ambiguous at all. What you _can_ say is that all variables are lvalues (5.1.1/8). – MSalters Dec 11 '14 at 00:09
I might not have the ultimate answer for you, but I know some things that are different:
Void pointers can point to anything. Literally! This means you have to know what you are pointing when using void pointers, otherwise you can mess a lot in your program. This means you need to know the type by compile time to use it correctly. That's why functions that deal with void pointer asks for its type size (using
sizeof
) and things like that along with the pointer.Objects are the base for any class you create in C#. But different from C/C++ you can know its type using reflection. This means you can deal with it no matter if you don't know the type previously. Also, Objects are C# objects... this means you are not referencing anything at all... you are referencing C# instances, no mater what type it might be.

- 1,943
- 1
- 16
- 25