Wrapping C++ Member Function Calls

Wrapping C++ Member Function Calls

Wrapping C++ Member Function Calls Bjarne Stroustrup AT&T Labs - Research Florham Park, New Jersey USA ABSTRACT This paper presents a simple, general, and efficient solution to the old problem of ``wrapping'' calls to an object in pairs of prefix and suffix code. The solution is also non-intrusive, applies to existing classes, allows the use of several prefix/suffix pairs, and can be implemented in 15 simple lines of Standard C++. A robust version of the wrapper is also presented. The claim of efficiency is backed by measurement. The paper is organized around a series of examples evolving the basic idea into a final robust template class. 1 Introduction Often, we want to ``wrap'' a piece of code with some prefix code and some suffix code. For example: ggr ra ab b -llo oc ck k ddo o -sso om me et th hi in ng g rre el le ea as se e -llo oc ck k bbe eg gi in n -ttr ra an ns sa ac ct ti io on n ddo o -sso om me et th hi in ng g een nd d -ttr ra an ns sa ac ct ti io on n ttr ra ac ce e -een nt tr ry y ddo o -sso om me et th hi in ng g ttr ra ac ce e -eex xi it t Typically, there is a prefix/suffix pair that should be applied to many different sections of code. In particu- lar, in a language with classes ± such as C++ ± the problem often becomes one of ensuring that a ppr re ef fi ix x () is called before a call of a member function and ssu uf ff fi ix x () after the call. This is easily achieved explicitly for a few calls. For example: vvo oi id d ffc ct t (X * p ) { ppr re ef fi ix x (); p ->f (); ssu uf ff fi ix x (); ppr re ef fi ix x () p ->g (); ssu uf ff fi ix x (); } However, application programmers must remember to bracket each call in its proper ppr re ef fi ix x ()/ssu uf ff fi ix x () calls. This is tedious and error prone. The obvious alternative is to add the ppr re ef fi ix x ()/ssu uf ff fi ix x () calls to the definitions of the member functions that need them. For example: ccl la as ss s X { ppu ub bl li ic c : vvo oi id d f () { ppr re ef fi ix x (); / * f Âs oow wn n sst tu uf ff f */ ssu uf ff fi ix x (); } vvo oi id d g () { ppr re ef fi ix x (); / * g Âs oow wn n sst tu uf ff f */ ssu uf ff fi ix x (); } // ... }; Published in the June 2000 issue of "The C++ Report". All rights reserved - 2 - vvo oi id d ffc ct t (X * p ) { p ->f (); p ->g (); } This solves the problem for the class user, but is still tedious for the class implementer. Worst of all, this solution requires foresight by the class implementer. Because the solution is intrusive ± the class member function code must be modified to add, remove, or change a suffix ± wrapping can only be done by some- one able and willing to modify the source code. One advantage of this approach is that it allows some, but not all functions to be wrapped. This can sometimes be a significant advantage. Consider the case where the prefix/suffix provides locking. That is, the class is a form of monitor [Hoare,1974]. In that case, it is not uncommon that a few functions can be performed without locking because they don't modify shared data or access only data that is accessed and modified atomically [Mitchell,1979]. This paper will concentrate on the case where every operation on a class needs to be wrapped. 2 History ``Wrapping'' is an old problem that has been solved many times in various languages and contexts. Moni- tors provide a solution to the problem of controlling access to a resource in a concurrent system by wrap- ping calls in a acquire-lock-or-wait and release-lock pair. Many languages provide primitives for wrapping code in acquire/release lock pairs (for example, Mesa's MMO ON NI IT TO OR R [Mitchell,1979], Java's ssy yn nc ch hr ro on ni iz ze ed d [Lea,1997], and Modula-3's LLO OC CK K [Nelson,1991]). More general solutions are provided by CLOS where a pair of :bbe ef fo or re e and :aaf ft te er r methods can wrap calls to objects of classes derived from the one providing the :bbe ef fo or re e and :aaf ft te er r methods [Keene,1989]. I briefly adopted a variant of that idea for C++'s direct ancestor C with Classes [Stroustrup,1994]. There, one could define a function that would implicitly be called before every call of every member function (except the constructor) and another that would be implicitly called before every return from every member func- tion (except the destructor). The functions providing this prefix/suffix semantics were called cca al ll l () and rre et tu ur rn n (). They were used to provide synchronization for the monitor class in the original task library [Stroustrup,1980]: ccl la as ss s mmo on ni it to or r { // ... cca al ll l () { /* grab lock */ } rre et tu ur rn n () { /* release lock */ } // ... }; ccl la as ss s X : ppu ub bl li ic c mmo on ni it to or r { ppu ub bl li ic c : vvo oi id d f (); vvo oi id d g (); // ... }; vvo oi id d ffc ct t (X * p ) { p ->f (); // monitor::call(); f()'s own stuff; monitor::return() p ->g (); // monitor::call(); g()'s own stuff; monitor::return() } Call and return functions were removed from the language because nobody (but me) used them and because I completely failed to convince people that cca al ll l () and rre et tu ur rn n () had important uses. In 1988, Mike Tiemann suggested an alternative solution called ``wrappers'' [Tiemann,1988]: sst tr ru uc ct t ffo oo o { ffo oo o (); Äffo oo o (); Published in the June 2000 issue of "The C++ Report". All rights reserved - 3 - vvi ir rt tu ua al l iin nt t ()ffo oo o (iin nt t (ffo oo o ::* ppm mf f )(iin nt t ), iin nt t i ) // virtual wrapper { ppr re ef fi ix x (); iin nt t r = (tth hi is s ->*ppm mf f )(i ); // invoke a function ssu uf ff fi ix x (); rre et tu ur rn n r ; } iin nt t g (iin nt t ); vvi ir rt tu ua al l iin nt t h (iin nt t ); }; Such a wrapper function was syntactically identified by a pair of parentheses in front of the class name and would wrap calls to functions of its class. The first argument of a wrapper was the member function to invoke, the second and subsequent arguments were the arguments to that function. The basic idea was that a member function called by a user was transformed a call of the wrapper with the arguments needed for the wrapper to do the actual call. For example: vvo oi id d ffc ct t (ffo oo o * p ) { iin nt t i = p ->g (1 ); // p->()foo(&foo::f,1) iin nt t j = p ->h (2 ); // p->()foo(&foo::g,2) // ... } This proposal died ± after some experimental use ± because of complexities of handling argument and return types, and because it was intrusive. That is, you wrapped a class by deriving it from a wrapper base class and that base class had to be written to deal with all combinations of argument and return types needed by the derived classes. This required too much foresight. This proposal had the interesting property that the wrapper had access to the arguments and the return value of a call. Also, different wrapper functions could be provided for functions with different types. 3 Prefix In the following sections, a solution to the wrapping problem is introduced in stages. The solution does not require language changes; it consists of two simple template classes. Overloading the -> has long been a popular way of specifying a prefix. For example: tte em mp pl la at te e <ccl la as ss s T > ccl la as ss s PPr re ef fi ix x { T * p ; ppu ub bl li ic c : PPr re ef fi ix x (T * ppp p ) :p (ppp p ) { } T * oop pe er ra at to or r ->() { /* prefix code */ rre et tu ur rn n p ; } }; X mmy y _ oob bj je ec ct t ; PPr re ef fi ix x <X > ppr re ef f _ oob bj j (&mmy y _ oob bj je ec ct t ); // available for prefixed use vvo oi id d ffc ct t (PPr re ef fi ix x <X > p ) { p ->f (); // prefix code; f() p ->g (); // prefix code; g() } Note how the prefix is attached to the object (and its functions) non-intrusively. I can use PPr re ef fi ix x to control access to classes that I cannot change. I can also use PPr re ef fi ix x to control access to classes that have not been specifically been designed for controlled access. In this, the templated PPr re ef fi ix x approach is more general and more flexible than the C with Classes approach and the Tiemann wrapper approach.

View Full Text

Details

  • File Type
    pdf
  • Upload Time
    -
  • Content Languages
    English
  • Upload User
    Anonymous/Not logged-in
  • File Pages
    12 Page
  • File Size
    -

Download

Channel Download Status
Express Download Enable

Copyright

We respect the copyrights and intellectual property rights of all users. All uploaded documents are either original works of the uploader or authorized works of the rightful owners.

  • Not to be reproduced or distributed without explicit permission.
  • Not used for commercial purposes outside of approved use cases.
  • Not used to infringe on the rights of the original creators.
  • If you believe any content infringes your copyright, please contact us immediately.

Support

For help with questions, suggestions, or problems, please contact us