summaryrefslogtreecommitdiff
path: root/docs/tutorials/012/page03.html
blob: c0a94ee30a1bc9c10ad27fa60c727b39139af7c0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
<HTML>
<HEAD>
   <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
   <META NAME="Author" CONTENT="James CE Johnson">
   <TITLE>ACE Tutorial 012</TITLE>
</HEAD>
<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F">

<CENTER><B><FONT SIZE=+2>ACE Tutorial 012</FONT></B></CENTER>

<CENTER><B><FONT SIZE=+2>Passing classes through ACE_Message_Queue</FONT></B></CENTER>


<P>
<HR WIDTH="100%">
<P>
In the previous tutorial we moved our complex data into the queue by
copy()ing it directly into the message block's data area.  I hope that 
most readers got a queasy feeling when I did that.  It just isn't a
good idea...
<P>
A better idea would be to teach the message queue about our data types 
(or at least a baseclass) so that it can more efficiently handle things:
<P>
<HR WIDTH="100%">
<PRE>
/*
  We derive a Message_Block from ACE_Message_Block and teach it about
  our Unit_Of_Work object.  When our task's svc() method pulls a block 
  out of the queue, it can then invoke the virtual methods of the work 
  object safely.  In this implementation we've also retained the
  original ACE_Message_Block functionallity so that we can use the
  underlying ACE_Data_Block objects to store data other than our
  Unit_Of_Work.
*/
class Message_Block : public ACE_Message_Block
{
public:
    typedef ACE_Message_Block inherited;

     /*
       Construct our underlying ACE_Message_Block with the requested
       data size and initialize our Unit_Of_Work pointer with the
       given object instance.  Note that this Message_Block instance
       now assumes ownership of the Unit_Of_Work and will delete it
       when the Message_Block is deleted.
     */
    Message_Block( size_t size, Unit_Of_Work * _data )
            : inherited(size), data_(_data)
        {
            ACE_DEBUG ((LM_DEBUG, "(%P|%t) Message_Block ctor 0x%x for 0x%x\n", (void *) this, data_));
        }

	~Message_Block(void)
        {
            ACE_DEBUG ((LM_DEBUG, "(%P|%t) Message_Block dtor 0x%x for 0x%x\n", (void *) this, data_));
            delete data_;
        }

     /*
       Return the Unit_Of_Work so that the task can invoke methods on
       it.
     */
    Unit_Of_Work * data(void)
        {
            return this->data_;
        }

protected:
    Unit_Of_Work * data_;

     /*
       Disallow these very dangerous operations.
       If we were to copy a Message_Block object then the data_
       pointer would get copied and we would eventually end up
       deleting the same object multiple times!  That's not good.  By
       preventing the copy, we can avoid this.
     */
    Message_Block &operator= (const Message_Block &);
    Message_Block (const Message_Block &);
};
</PRE>
<HR WIDTH="100%">
<P>
Ok, this looks pretty good.  We just construct our specialized
Message_Block instead of the generic ACE_Message_Block and let it
carry our data along.  When our application is done with the message
block and release()es it, we know that our work object will also be
taken care of.
<P>
Let's now go to main() and see what we had to change there to use this 
specialization.
<P>
<HR WIDTH="100%">
<P>
<CENTER>[<A HREF="..">Tutorial Index</A>] [<A HREF="page04.html">Continue
This Tutorial</A>]</CENTER>

</BODY>
</HTML>