21

I have a C++ program:

struct arguments
{
  int a, b, c;  
  arguments(): a(3), b(6), c(9) {}
};

class test_class{
  public:

    void *member_func(void *args){
      arguments vars = (arguments *) (*args); //error: void is not a 
                                              //pointer-to-object type

      std::cout << "\n" << vars.a << "\t" << vars.b << "\t" << vars.c << "\n";
    }
};

On compile it throws an error:

error: ‘void*’ is not a pointer-to-object type

Can someone explain what I am doing wrong to produce this error?

Eric Leschinski
  • 146,994
  • 96
  • 417
  • 335
Matt Munson
  • 2,903
  • 5
  • 33
  • 52
  • Yes, there is. Have you tried giving `args` another datatype? – Blender Oct 31 '11 at 03:34
  • 2
    You don't have any "abstract types" (I assume you mean abstract base classes) in this example. You probably mean `*(arguments *)args`, which casts `args` from a `void *` to an `arguments *`, _then_ dereferences it. Your current code tries to dereference a `void *` (which is illegal), then cast the dereferenced value to an `arguments *`, which is almost certainly not what you intended. – Chris Lutz Oct 31 '11 at 03:34
  • @Chris Yeah that is what I was trying to do, thanks for the clarification. Btw, I thought structs and classes were considered to be abstract types while eg. int, float are non abstract. – Matt Munson Oct 31 '11 at 03:37
  • 1
    Also, your `member_func` returns `void *` but you don't have a `return` statement in it anywhere. Also, why do you need to use `void *`? Why can't you just use `arguments *` (or, better yet, just `arguments`, or `const arguments&`)? – Chris Lutz Oct 31 '11 at 03:38
  • @MattMunson - No, "abstract" refers to classes (or structs) with pure virtual member functions. I don't know how much C++ you know, but if you're in a C++ course (which is my guess), then you'll get to that point eventually, so don't worry about it for now. – Chris Lutz Oct 31 '11 at 03:39
  • @Chris good to know about the abstract types. I'm in the midst of coding functions with equivalent headers so they can be used with `pthread_create()` from the pthread library. Just using this code to demonstrate the problem I'm having. – Matt Munson Oct 31 '11 at 03:43
  • @MattMunson - For `pthread_create`'s `start_routine` argument, you can't use a member function - it has to be a standalone function or a `static` function in a class. Member functions have a hidden extra argument for `this`, so it won't be called at the machine level the way `pthread_create` expects it to be. – Chris Lutz Oct 31 '11 at 03:46
  • @Chris I suppose then I can just use a generic function and then pass the object using the void pointer, and then call the member function from there. – Matt Munson Oct 31 '11 at 04:07

6 Answers6

33

You are dereferencing the void * before casting it to a concrete type. You need to do it the other way around:

arguments vars = *(arguments *) (args);

This order is important, because the compiler doesn't know how to apply * to args (which is a void * and can't be dereferenced). Your (arguments *) tells it what to do, but it's too late, because the dereference has already occurred.

bdonlan
  • 224,562
  • 31
  • 268
  • 324
  • 1
    But please use `static_cast` here -- you'd get a better error message that way... – Billy ONeal Oct 31 '11 at 04:30
  • @Billy what does `static_cast` do? – Matt Munson Oct 31 '11 at 07:47
  • 1
    @Matt: Same thing as a C style cast, except more limited. `static_cast` disallows removal of `const`, reinterpretation of a pointer type, and a few other nasty things. Generally speaking, anything that `static_cast`s will work across platform/architectures. See section 5.2.9 of the C++ standard for more details (assuming C++03) – Billy ONeal Oct 31 '11 at 14:32
10

Bare bones example to reproduce the above error:

#include <iostream>
using namespace std;
int main() {
  int myint = 9;             //good
  void *pointer_to_void;     //good
  pointer_to_void = &myint;  //good

  cout << *pointer_to_void;  //error: 'void*' is not a pointer-to-object type
}

The above code is wrong because it is trying to dereference a pointer to a void. That's not allowed.

Now run the next code below, If you understand why the following code runs and the above code does not, you will be better equipped to understand what is going on under the hood.

#include <iostream>
using namespace std;
int main() {
    int myint = 9;
    void *pointer_to_void;
    int *pointer_to_int; 
    pointer_to_void = &myint;
    pointer_to_int = (int *) pointer_to_void;

    cout << *pointer_to_int;   //prints '9'
    return 0;
}
Eric Leschinski
  • 146,994
  • 96
  • 417
  • 335
5

You have the * in the wrong place. So you're trying dereference the void*. Try this instead:

arguments vars = *(arguments *) (args);
std::cout << "\n" << vars.a << "\t" << vars.b << "\t" << vars.c << "\n";

Alternatively, you can do this: (which also avoids the copy-constructor - as mentioned in the comments)

arguments *vars = (arguments *) (args);
std::cout << "\n" << vars->a << "\t" << vars->b << "\t" << vars->c << "\n";
Mysticial
  • 464,885
  • 45
  • 335
  • 332
  • Leaving it as a pointer is probably better, since it avoids a copy constructor. However, the OP should make the pointer (both `arguments *` and `void *`) `const`. – Chris Lutz Oct 31 '11 at 03:35
2

The problem as bdonlan said is "dereferencing void* before casting".

I think this example would help:

#include <iostream>

using namespace std;

int main()
{



   void *sad;
   int s = 23;
   float d = 5.8;

   sad = &s;
   cout << *(int*) sad;//outputs 23//wrong: cout << *sad ;//wrong: cout << (int*) *sad;



   sad = &d;
   cout << *(float *) sad;//outputs 5.8//wrong: cout << *sad ;//wrong: cout << (float*) *sad;

   return 0;
}
Gandalf
  • 2,921
  • 5
  • 31
  • 44
0

The problem above there is that you are trying to deference a void pointer which is not allowed in C or C++.

However, this still works:

#include <iostream>
using namespace std;
int main()
{
    int b=10;
    void *a=&b;
    int *ptr=(int*)a;
    cout<<*ptr;;
} 

We can deference int* pointers after casting void pointers to int* pointers.

0

*args means "the object(value) args points to". Therefore, it can not be casted as pointer to object(argument). That's why it is giving error

user966379
  • 2,823
  • 3
  • 24
  • 30