Solved

Void pointers

Posted on 2006-11-15
13
985 Views
Last Modified: 2008-02-01
Hi there,

When a function expects void pointer, can I pass in a pointer to an object to it. I am using a queue API(don't have the code).  The Queue has the following functions.  

Receive (void* pMsgBuffer, int size);
Send (const void* pMsgBuffer,int size)



If I want to pass in 'tc' below and then at the receiving side copy to tc2.  Can I do these??

TestClass *tc = new TestClass( );

TestClass tc2r;

Send(tc, sizeof(TestClass))
Receive(&tc2, sizeof(TestClass))

0
Comment
Question by:ambuli
  • 3
  • 2
  • 2
  • +5
13 Comments
 
LVL 45

Expert Comment

by:sunnycoder
Comment Utility
Hi ambuli,

> When a function expects void pointer, can I pass in a pointer to an object to it
Yes you can ... The code snippets you posted would work fine ... any pointer can be casted to a void * and void * can be cast to pointer of any other type. const may give you a warning which can be avoided by an explicit cast.

Cheers!
sunnycoder
0
 

Author Comment

by:ambuli
Comment Utility
Thanks SunnyCoder,

Here is a little expanded version. I am having problems with the following code.  Please help.  The problem is that when I print the member, expecting to see 100, it becomes empty.  

class A
{
   public:
      virtual void setmember( )=0;
      virtual void printMember( );
 };

class B : public A
{
public:
    void setMember( int x){ m_b = x; };
    void printMember( cout << "member = " << m_b << endl;
private:
    int m_b;
};

class C
{
       testSend( A *a) { Send(a, sizeof(A) ); };
       testReceive( A *a) { Receive( a, sizeof(A)) };

};

main()
{
    C  *cc = new C( )

    B *bb = new B( );
    B  bb2;
    bb->setMember(100);
    cc->testSend(bb, sizeof(A));
    cc->testReceive(&bb2, sizeof(A));
    bb2.printMember();

}
0
 
LVL 45

Expert Comment

by:sunnycoder
Comment Utility
Hi ambuli,

You are calling printMember() on bb2 and you have not initialized bb2!!
Also, this is not the exact code you are using ... this wont compile!!

Cheers!
sunnycoder
0
 
LVL 11

Expert Comment

by:DeepuAbrahamK
Comment Utility
Hi Ambuli,

The void * pointer is a place-holder pointer which any pointer type can be converted to, this is used so that any data type can be put on the "queue" in your example.

In your code:

TestClass *tc = new TestClass( );
TestClass tc2r;

Send(tc, sizeof(TestClass))
Receive(&tc2, sizeof(TestClass))

This might work but we cannot just pass any pointer in this case, unless you have control over the functions Send & Receive just because we don't know how "tc" will be reinterpreted in side the function. If there is an SDK and it expects only 2 or 3 verities of void pointers then its fine.When I say 2 or 3 verities of void pointer, it means, for examole an object of TestClass1 or TestClass2 or TestClass3.

Hope I get across.

Best Regards,
DeepuAbrahamK


0
 

Author Comment

by:ambuli
Comment Utility
Yes, it is not the exact code.  The code is very long to post here.  
Even if changing it didn't help.

   B  *bb2 = new B( );
   bb->setMember(100);
   cc->testSend(bb, sizeof(A));
   cc->testReceive(bb2, sizeof(A));
   bb2->printMember();
0
 
LVL 45

Expert Comment

by:sunnycoder
Comment Utility
Hi ambuli,

>    B  *bb2 = new B( );  ----- allocated bb2
>    bb->setMember(100);        ---- set bb
>    bb2->printMember();          ----- print bb2!!!!

I dont see void * or class C playing any role here ... If you are observing some unexpected behavior, look for flaws in the logic of the code ... casting to and from void * wont cause any problems as long as you are correctly handling the data which these pointers are pointing to.

Cheers!
sunnycoder
0
How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

 
LVL 8

Expert Comment

by:deepu chandran
Comment Utility
hi,
  I found mistake over here,
>>  void printMember( cout << "member = " << m_b << endl;

void PrintMember() { cout << "member = " << m_b << endl;}

Deepu

0
 
LVL 2

Accepted Solution

by:
numansiddique earned 300 total points
Comment Utility
Hi Ambuli,
if the Send function casts the void pointer to Class A type, it cannot access the m_b variable because it has been declared in Class B and not in Class A.
A parent Class cannot access the member functions and variables of its derived classes.  
You have to declare m_b in the class A instead of declaring it in the Class B. may be because of this you are not able to see the desired output when you print it.
hope this might help you

Numan
0
 
LVL 39

Assisted Solution

by:itsmeandnobodyelse
itsmeandnobodyelse earned 200 total points
Comment Utility
>>>> If I want to pass in 'tc' below and then at the receiving side copy to tc2.

That doesn't work as long as you don't cast the pointer to A* or B* and make a copy using the appropriate copy constructor of class B. If you only make a 'flat' copy the 'data' members of the class and here only the 'A'  part - you passed sizeof(A) to Send - copying only would work if  class B had no data members at all and if all data members were of POD type - means no class members and no pointer members where the class is responsible for the storage.

Generally, passing void pointers shouldn't be done in C++. It is onyl senseful if you have to use an old C interface where the pointer simply was passed to some kind of callback function you could provide together with the pointer.

Then, your function can cast the void pointer to the correct type what is not really recommendable in C++ but safe.

Regards, Alex

P.S.

You shouldn't create pointers by using 'new' operator if you can do the same without pointers:

int main()
{
    C cc;
    B bb, bb2;    
    ....

    cc.Send(&bb);
    ..,
}

Also, avoid pointers in the argument list and pass references instead. Use const references whenever you don'rt want to change the objects.


0
 
LVL 17

Expert Comment

by:rstaveley
Comment Utility
Take heed of Alex's advice, but as long as your class is a self-contained bunch of bits (or POD = plain old data class) you can serialise and deserialise by doing bitwise copies. Beware that if you are doing this over the network your receipient may have different endianism, different word sizes and different packing from your sender. So it is a bad plan.

e.g. Illustration:
--------8<--------
#include <iostream>
#include <string>
using namespace std;

class BunchOfBits;
ostream& operator<<(ostream& os,const BunchOfBits&);

class BunchOfBits {
      char name[100];
      int value;
      friend ostream& operator<<(ostream& os,const BunchOfBits&);

public:
      BunchOfBits(const string& name,int value) : value(value) {
            strncpy(BunchOfBits::name,name.c_str(),sizeof(BunchOfBits::name)-1);
            BunchOfBits::name[sizeof(BunchOfBits::name)-1] = '\0';
      }
};

ostream& operator<<(ostream& os,const BunchOfBits& bob) {
      return os << "Bob '" << bob.name << "' born " << bob.value;
};

char network_buffer[1024];
size_t occupied = 0U;

size_t send(const void *data,size_t length)
{
      if (occupied)
            return 0U;
      if (length > sizeof(network_buffer))
            length = sizeof(network_buffer);
      memcpy(network_buffer,data,length);
      occupied = length;
      return length;
}

size_t receive(void *data,size_t length)
{
      if (!occupied)
            return 0U;
      if (length > occupied)
            length = occupied;
      memcpy(data,network_buffer,length);
      occupied = 0U;
      return length;
}

int main()
{
      BunchOfBits first("Robert The Bruce",1274);
      BunchOfBits second("Robert Louis Stevenson",1894);
      BunchOfBits third("Robert Smith (The Cure)",1959);

      cout << "1st: " << first << ", 2nd: " << second << ", 3rd: " << third << '\n';

      send(&first,sizeof(BunchOfBits)); // Let's send the first Bob
      receive(&third,sizeof(BunchOfBits)); // And receive him as the 3rd

      cout << "1st: " << first << ", 2nd: " << second << ", 3rd: " << third << '\n';
}
--------8<--------
0
 
LVL 22

Expert Comment

by:grg99
Comment Utility
You really can't in general pass objects as voids.  Objects can have very complex internal info, such as pointers to virtual method tables-- stuff that doesnt make any sense outside of the sending program.

You CAN send the fields of an object, if you explicitly list them and their lengths, but that gets cumbersome.

A better solution is to encapsulate all thee data into a sepoarate struct, then send that.
0
 
LVL 39

Expert Comment

by:itsmeandnobodyelse
Comment Utility
>>>> you can serialise and deserialise by doing bitwise copies.

Instead of bitwise copies - what rarely is an option - you should provide member functions to serialize and deserialize together with your class, e. g. together with an intelligent buffer or stream class like the one below.

Regards, Alex


struct Buffer
{
     Buffer(unsigned int siz) : m_siz(siz), m_len(0), m_pBuf(new unsigned char[siz+1]) {}
       ~Buffer() { delete [] m_pBuf; }

       operator void*() { return m_pBuf; }
       Buffer&  operator += (const Buffer& b)
       {
          int nlen = m_len + b.m_len;
          if (m_siz < nlen)
            {
               unsigned char* pBuf = new unsigned char[nlen + nlen];
               memcpy(pBuf, m_pBuf, m_len);
               m_siz = nlen + nlen;
               delete [] m_pBuf;
               m_pBuf = pBuf;
            }
            memcpy(&m_pBuf[m_len], b.m_pBuf, b.m_len);
            m_len += b.m_len;
            return *this;
       }

       Buffer&  operator -= (unsigned int len)
       {
           if (b.m_len > len)
             memmove(b, &b.m_pBuf[slen], b.m_len - slen);
             b.m_len -= len;
             return *this;
       }
       int            size() { return m_size; }
       int m_siz;
       int m_len;
       unsigned char* m_pBuf;
};

Buffer& operator<<(Buffer& b, const string& s)
{
    int  len = s.length()+1;
    Buffer temp(len + sizeof(int));
      memcpy(temp, &len, sizeof(int));
      memcpy(temp, s.c_str(), len);
      return b += temp;
}

Buffer& operator<<(Buffer& b, int i)
{
    Buffer temp(sizeof(int));
      memcpy(temp, &i, sizeof(int));
      return b += temp;
}

Buffer& operator<<(Buffer& b, const char* s)
{
    b << string(s);
      return b;
}

Buffer& operator<<(Buffer& b, const X& x)
{
    Buffer temp(sizeof(X));  // take sizeof X as approximate size
      x.serialize(temp);
   
      return b += temp;
}

Buffer& operator>>(Buffer& b, string& s)
{
    int slen;
      memcpy(&slen, b, sizeof(int));
      b -= sizeof(int);  // cut length info

      s = (const char*)(void*)b; // assume zero-terminated strings only

      b -= slen;
    return b;
}

Buffer& operator>>(Buffer& b, int& i)
{
      memcpy(&i, b, sizeof(int));
      b -= sizeof(int);  // cut length info
      return b;
     
}

Buffer& operator>>(Buffer& b, char* psz)
{
    string s;
    b >> s;
      strcpy(psz, s.c_str());
      return b;
}

Buffer& operator>>(Buffer& b, X& x)
{
    b = x.deserialize(b);
    return b;    
}



class A
{
     
public:  
     Buffer& serialize(Buffer b);
       Buffer& deserialize(Buffer& buf);
private:
     string m_s;
       int    m_i;
       char   m_c[100];
       X      m_x;
       // more ...
};

Buffer& A::serialize(Buffer& b)
{
   b << m_s << m_i << m_c << m_x;
   return b;
}

Buffer& A::deserialize(Buffer& b)
{
   b >> m_s >> m_i >> m_c >> m_x;
   return b;
}


int main()
{
      A a1;  
      
      // fill data
    a1.fill();

    Buffer buf1(sizeof(A));
      a1.serialize(buf1);
    send(buf1, buf1.m_len);

      ....

      A a2;

    Buffer buf2(MAX_SIZ_TO_RECEIVE);
    receive(buf2, buf2.m_siz);
      a2.deserialize(buf2);

      // note, the receive buffer can contain more data

      ...

      return 0;

}
0
 
LVL 17

Expert Comment

by:rstaveley
Comment Utility
I'm really not promoting bitwise serialising, because it is bad for all the reasons listed above, but if you are using the approach, because "you know the layout of your bits" (snigger), you have an opportunity to play with placement construction.

With reference to my previous code example, see how we can receive fourth from a sent BunchOfBits using placement construction:

      char fourth_buf[sizeof(BunchOfBits)];
      receive(&fourth_buf,sizeof(BunchOfBits));  
      BunchOfBits& fourth = *new(fourth_buf) BunchOfBits();      // Placement ctor

Note that you need a default Ctor for BunchOfBits to do placement construction thus. That's something I omitted.

Placement construction can be used to "construct" objects from suitably laid out raw memory. It is of course not managed by the heap in this case, which is why you see me make fourth a reference.
0

Featured Post

IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

Join & Write a Comment

Templates For Beginners Or How To Encourage The Compiler To Work For You Introduction This tutorial is targeted at the reader who is, perhaps, familiar with the basics of C++ but would prefer a little slower introduction to the more ad…
What is C++ STL?: STL stands for Standard Template Library and is a part of standard C++ libraries. It contains many useful data structures (containers) and algorithms, which can spare you a lot of the time. Today we will look at the STL Vector. …
The viewer will learn how to clear a vector as well as how to detect empty vectors in C++.
The viewer will be introduced to the technique of using vectors in C++. The video will cover how to define a vector, store values in the vector and retrieve data from the values stored in the vector.

772 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

13 Experts available now in Live!

Get 1:1 Help Now