Click here to Skip to main content
15,892,839 members
Articles / Programming Languages / C++

Two-thirds of a pimpl and a grin

Rate me:
Please Sign up or sign in to vote.
4.74/5 (14 votes)
5 Jun 2014CPOL9 min read 90.6K   124   31  
An article on a quasi-pimpl, as well as a neat global object manager.
#ifndef DwlGrinPtrH
#define DwlGrinPtrH

#ifndef ARG_COMPILER_H
#include "arg_compiler.h"
#endif

#ifndef ARG_DEEP_COPY_UTILS_H
#include "arg_deep_copy_utils.h"
#endif

#include ARG_STLHDR(algorithm)

// =================================================================================
// The following is adopted from Alan Griffith's grinPtr.  The changes made allow
// you to hold off constructing the 'pointee' until any time you choose - you don't
// have to construct it in the initializer list of a class.  I have also added a
// 'reset' function and a 'release' function, in order to give the maximum
// flexibility to the end programmer.
//
// Note that if you use these abilities, the class is not 'truly' safe, as you could
// theoretically try to construct an object held by a 'NULL' grinPtr using the
// copy constructor, and it would blow up terribly.  Therefore, the end-programmer
// must keep this in mind whenever copying arg::grinPtr objects.
//
// For this reason, I have placed this into the dwl namespace, to differentiate
// it from Alan's original work.
//
// David O'Neil
// =================================================================================

/** \file arg_grin_ptr.h
*
*   grinPtr<> - Provides support for "Cheshire Cat" idiom
*
*   Modification History
*<PRE>
*   06-Apr-00 : Reworked documentation following user feedback  Alan Griffiths
*   04-Nov-99 : Revised copyright notice						Alan Griffiths
*   21_Sep-99 : Original version                                Alan Griffiths
*</PRE>
**/


/**
*   arglib: A collection of utilities. (E.g. smart pointers).
*   Copyright (C) 1999, 2000 Alan Griffiths.
*
*   This code is part of the 'arglib' library. The latest version of
*   this library is available from:
*
*      http:www.octopull.demon.co.uk/arglib/
*
*   This code may be used for any purpose provided that:
*
*   1. This complete notice is retained unchanged in any version
*       of this code.
*
*   2. If this code is incorporated into any work that displays
*       copyright notices then the copyright for the 'arglib'
*       library must be included.
*
*   This library is distributed in the hope that it will be useful,
*   but WITHOUT ANY WARRANTY; without even the implied warranty of
*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
*   @author alan@octopull.demon.co.uk
**/
namespace arg {
   /**
   *  Pointer type to support "Cheshire Cat" idiom - only the indicated
   *  constructor requires access to the complete pointee type.
   *
   *  A const-qualified smart pointer that takes ownership of the
   *  referenced object and implements copy construction/assignment by
   *  copying the referenced object.
   *
   *  The correct algorithm for copying is resolved by using the
   *  arg::deep_copy() template.  This means that the referenced object
   *  will be  copied using the copy construction unless it is tagged
   *  by inheriting from arg::cloneable or an overload of arg::deep_copy()
   *  is provided.
   *
   *  All methods support the strong exception safety guarantee with the
   *  proviso that the referenced type must have a non-throwing destructor.
   *
   *                                               @author Alan Griffiths
   **/
   template<typename p_type>
   class grinPtr {
         ///
            typedef void (*delete_ftn)(p_type* p);
   	
         ///
            typedef p_type* (*copy_ftn)(const p_type* p);

      public:
      //  Construction & assignment

         /// Construct owning p - p_type must be a complete type
	      explicit grinPtr(p_type* pointee) : do_copy(&my_copy_ftn), p(pointee),
	                  do_delete(my_delete_ftn) {
	               
            // "sizeof(p_type)" will force a diagnostic for an incomplete type
            sizeof(p_type);
            }
   	
   	   //Allow to hold a NULL default parameter (Added by David O'Neil)
   	   //Note that this type doesn't allow for any copying via deep_copy.
         grinPtr() : do_copy(&no_copy_ftn), p(NULL), do_delete(my_delete_ftn) { }

	      /// Makes a copy of the object referenced by rhs
	      grinPtr(const grinPtr& rhs);

	      /// Destroys the referenced object
	      ~grinPtr() throw()              { do_delete(p); }


      //  Accessors - (overloaded on const)

	      /// Return contents (const)
	      const p_type* get() const        { return p; }

	      /// Return contents (non-const)
	      p_type* get()                    { return p; }

	      /// Indirection operator (const)
	      const p_type* operator->() const { return p; }

	      /// Indirection operator (non-const)
	      p_type* operator->()             { return p; }

         void reset(p_type * ptr = NULL) { do_delete(p); p = ptr; } //Added by David O'Neil

         void release() { p = NULL; } //Give programmer the option.  Added by David O'Neil

	      /// Dereference operator (const)
	      const p_type& operator*() const	 { return *p; }

	      /// Dereference operator (non-const)
         p_type& operator*()              { return *p; }


      //  Mutators

	      /// Swaps contents with "with"
	      void swap(grinPtr& with) throw() { 
	         p_type* pp = p; p = with.p; with.p = pp; }
   	
	      /// Makes a copy of the object referenced by rhs (destroys old)
	      grinPtr& operator=(const grinPtr& rhs);


      private:
	      copy_ftn	do_copy;
	      p_type*		p;
	      delete_ftn	do_delete;

         static void my_delete_ftn(p_type* p) {
            delete p;
            }
   	
         static p_type* my_copy_ftn(const p_type* p) {
            return arg::deep_copy(p);
            }
        
         static p_type* no_copy_ftn(const p_type* p) {
            return NULL;
            }
      };


   template<typename p_type>
   inline grinPtr<p_type>::grinPtr(const grinPtr& rhs) :
               do_copy(rhs.do_copy), p(do_copy(rhs.p)), do_delete(rhs.do_delete) {
                  
      }
        
   template<typename p_type>
   inline grinPtr<p_type>& grinPtr<p_type>::operator=(const grinPtr& rhs) {
	   p_type* pp = do_copy(rhs.p);
	   do_delete(p);
	   p = pp;
	   return *this;
      }
   }

namespace std {
   /// Overload swap algorithm to provide an efficient, non-throwing version
   template<class p_type>
   inline void swap(::arg::grinPtr<p_type>& lhs, ::arg::grinPtr<p_type>& rhs) throw() {
      lhs.swap(rhs);
      }
   }
   
#endif

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer www.randommonkeyworks.com
United States United States
I am the author of Laughing at the Devil: One Man’s Religious Discoveries. If you want to understand the astronomic investigations of our priests 3,000 years ago, LATD is the book to turn to. It opens up the thoughts that pushed them away from their earlier polytheism and towards our current definition of God.

Trained as a mechanical engineer, I have been involved with design, supervision, and project management. I taught myself C++ programming in order to play around with binaural beats more easily. I've also created various databases to help with project management and personal tasks.

Databases are cool and extremely useful! Happy coding, everybody!

Comments and Discussions