Pointers/Memory Allocation   «Prev  Next»
Lesson 6 Generic pointer type
Objective Examine the generic pointer type void*.

C++ Generic Pointer Type

The keyword void is used as the return type of a function not returning a value and to indicate an empty argument list to a function. More important in C++, however, is the use of void* as a generic pointer type.
A generic pointer can be assigned a pointer value of any type, but it may not be dereferenced. It would not make sense to dereference a pointer to a void value.

Pointer casts

Unlike ANSI C, a generic pointer is not assignment-compatible with an arbitrary pointer type. This means C++ requires that generic pointers be cast to an explicit type for assignment to a nongeneric pointer value.

A void* is a pointer, but the type that it points to is not known. A function that returns a void* generally is doing one of the following:
  1. It is dealing in unformatted memory. This is what operator new and malloc return: a pointer to a block of memory of a certain size. Since the memory does not have a type (because it does not have a properly constructed object in it yet), it is typeless, which means it is void.
  2. It is not clear what type of handle it is. It references a created object without naming a specific type. Code that does this is generally poorly formed, since this is better done by forward declaring a struct or class and simply not providing a public definition for it. Because then, at least it has a real type.
  3. It returns a pointer to storage that contains an object of a known type. However, that API is used to deal with objects of a wide variety of types, so the exact type that a particular call returns cannot be known at compile time. Therefore, there will be some documentation explaining when it stores which kinds of objects, and therefore which type you can safely cast it to.
Because it is easy to implement this construct incorrectly, and there is no way to ask if a particular usage is the right one, you should avoid implementing a generic pointer.
void* usage, especially in C++, should be rare, used primary for dealing in raw memory.


Examples

Here are some examples of legal and illegal expressions stemming from the use of void*:
void*  gp;    //generic pointer
int*  ip;     //int pointer
char*  cp;    //char pointer

gp = ip;      //legal conversion
ip = static_cast<int*>(gp); //explicit cast required
                            //in C++ but not in C
cp = ip;      //illegal conversion
*ip = 15;     //legal dereference of pointer to int
*ip = *gp;    //illegal generic pointer dereference

The C++ standard does not allow for the concept of generic pointer. You may or may not be able to get away with casting your function pointer to void* (*)(). In C++ there are standards for creating such a solution.

Example of pre-C++11 generic pointer:

struct Func
{
  virtual void* operator()() = 0;
  virtual ~func(){}
};

template <typename T>
struct FuncImpl
{
  typedef T TFunc();
  FuncImpl (TFunc* func) : m_func(func) {}
  void* operator()() { return m_func(); }
 private:
  TFunc* m_func;
};

How you can store shared_ptr<Func> in your vector. A much nicer solution in C++11 could look like this:

Generic pointer in C++ 11

template <typename T>
std::function<void*()> castToVoidFunc (T* (*func)())
{
  return [=](){ return func(); };
}

C++ How to Program