Solved

Void pointers

Posted on 2006-11-15
13
988 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
ID: 17953497
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
ID: 17953581
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
ID: 17953606
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
Free Tool: IP Lookup

Get more info about an IP address or domain name, such as organization, abuse contacts and geolocation.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

 
LVL 11

Expert Comment

by:DeepuAbrahamK
ID: 17953651
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
ID: 17953674
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
ID: 17953685
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
 
LVL 8

Expert Comment

by:deepu chandran
ID: 17953736
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
ID: 17953886
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
ID: 17954132
>>>> 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
ID: 17954287
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
ID: 17954945
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
ID: 17955250
>>>> 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
ID: 17957452
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

Free Tool: Port Scanner

Check which ports are open to the outside world. Helps make sure that your firewall rules are working as intended.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

In days of old, returning something by value from a function in C++ was necessarily avoided because it would, invariably, involve one or even two copies of the object being created and potentially costly calls to a copy-constructor and destructor. A…
Written by John Humphreys C++ Threading and the POSIX Library This article will cover the basic information that you need to know in order to make use of the POSIX threading library available for C and C++ on UNIX and most Linux systems.   [s…
The goal of the tutorial is to teach the user how to use functions in C++. The video will cover how to define functions, how to call functions and how to create functions prototypes. Microsoft Visual C++ 2010 Express will be used as a text editor an…
The viewer will learn how to user default arguments when defining functions. This method of defining functions will be contrasted with the non-default-argument of defining functions.

828 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