pImpl的高级用法

93 阅读3分钟

直接上代码

//这里是main函数的cPP文件

#include <stdlib.h>
#include <stdio.h>
#include <atomic>
#if defined( SCIPACK_CFG_USE_MEM_CNTR )
static std::atomic<int> g_malloc_cntr(0);
static std::atomic<int> g_new_cntr(0);
static void  incr_malloc_cntr( ) { g_malloc_cntr.fetch_add(1); }
static void  decr_malloc_cntr( ) { g_malloc_cntr.fetch_sub(1); }
static void  incr_new_cntr( )    { g_new_cntr.fetch_add(1); }
static void  decr_new_cntr( )    { g_new_cntr.fetch_sub(1); }
static int   curr_malloc_cntr( ) { return g_malloc_cntr; }
static int   curr_new_cntr( )    { return g_new_cntr; }
#else
static void  incr_malloc_cntr( ) { }
static void  decr_malloc_cntr( ) { }
static void  incr_new_cntr( ) { }
static void  decr_new_cntr( ) { }
static int   curr_malloc_cntr( ) { return 0; }
static int   curr_new_cntr( ) { return 0; }
#endif

#ifndef scipack_new
#define scipack_new( t, ... )  ( incr_new_cntr( ), new t ( __VA_ARGS__ ))
#define scipack_delete( p,t )  do{ decr_new_cntr( ); delete( ( t *)( p )); }while(0)
#endif

#ifndef scipack_malloc
#define scipack_malloc( sz )   ( incr_malloc_cntr(), malloc( sz ))
#define scipack_free( p )      do{ decr_malloc_cntr( ); free( p ); }while(0)
#endif

// ================================================================
// 重定义 new / delete ,这样我们能监视内存计数
// ================================================================
#define  SCIPACK_PImplPrivTemp_new     scipack_new
#define  SCIPACK_PImplPrivTemp_delete  scipack_delete
#include "pimplprivtemp.hpp"//这里引用了一个外部文件主要实现一些pimpl的特殊实例

// ================================================================
// 定义 PIMPL 内部类
// ================================================================
class TestPImp : public SciPack::PImplPrivTemp< TestPImp >
{
private:
int m_cntr;
public:
TestPImp (  ) { m_cntr = 0; }
TestPImp ( const TestPImp &ta )
{
printf(" TestPImpl Copy Constructor called\n");
m_cntr = ta.m_cntr;
}
virtual ~TestPImp(  ) { }

    int   cntr( ) { return m_cntr; }
void  setCntr( int c ) { m_cntr = c; }
};

// ==============================================================
//  定义 PIMPL 包装类
// 这个类将实现为 Copy On Write 机制
// ==============================================================
class Test {
private:
void *m_rsvd;
void *m_obj;
public:
Test (  ) { m_obj = nullptr; }
virtual ~Test(  ) {
if ( m_obj != nullptr )
{
TestPImp::attach( & m_obj, nullptr );
}
}
void  setCntr( int c )
{
TestPImp::buildIfNull( & m_obj )->duplicateIfShared( & m_obj )->setCntr( c );
}
int   cntr( )
{ return TestPImp::buildIfNull( & m_obj )->cntr();
}
Test & operator = ( const Test & t )
{
TestPImp::attach( & m_obj, ( void **)& t.m_obj );
return *this;
}
};

// ==============================================================
// 入口主函数
// ==============================================================
int main (  )
{
{
Test  ta;
printf(" ta. cntr = %d\n", ta.cntr());
printf(" current mem cntr: %d\n", curr_new_cntr());
ta.setCntr( 99 );
printf(" ta. cntr = %d\n", ta.cntr());

        Test  tb;
tb = ta;
printf(" tb. cntr = %d\n", tb.cntr());
printf(" current mem cntr: %d\n", curr_new_cntr());
tb.setCntr(100);

        printf(" ta. cntr = %d\n", ta.cntr());
printf(" tb. cntr = %d\n", tb.cntr());
printf(" current mem cntr: %d\n", curr_new_cntr());
}
printf("curr mem cntr: %d\n", curr_new_cntr( ));
return 0;
}

下面贴出:pimplprivtemp.hpp文件

/* / */
/*!
@file    pimplprivtemp.hxx
@author  night wing
@date    2017/01
@brief   The file declare the PImplPriv Template  Protocol
@par     History
@verbatim
<author>   <time>   <version>  <desc>                                  
nightwing   2017/01   0.1.0     build this module            
@endverbatim
*/
/* / */
#ifndef  __SCIPACK_PIMPLPRIVTEMP_HXX
#define  __SCIPACK_PIMPLPRIVTEMP_HXX

/*!
@addtogroup  SciPack
@{
*/

/*!
@addtogroup  devel
@{
*/

/*!
@addtogroup  devel_Exported_Classes
@{
*/


/* /
config
/
*/
#if !defined( SCIPACK_HIDDEN )
#if defined( _WIN32 ) || defined( __CYGWIN__ )
#define SCIPACK_HIDDEN
#else
#if __GNUC__ >= 4
#define SCIPACK_HIDDEN __attribute__ ((visibility ("hidden")))
#else
#define SCIPACK_HIDDEN
#endif
#endif
#endif

#ifndef SCIPACK_NAMESPACE_BEGIN
#define SCIPACK_NAMESPACE_BEGIN  namespace SciPack {
#define SCIPACK_NAMESPACE_END    }
#endif

#ifndef SCIPACK_CLASS
#define SCIPACK_CLASS( c )  SciPack::##c
#endif

#ifndef SCIPACK_CLASS_PTR
#define SCIPACK_CLASS_PTR( c, obj )  (( SciPack::##c *)( obj ))
#endif

#ifndef SCIPACK_PImplPrivTemp_new 
#define SCIPACK_PImplPrivTemp_new( t, ... )  ( new t( __VA_ARGS__ ))
#endif

#ifndef SCIPACK_PImplPrivTemp_delete
#define SCIPACK_PImplPrivTemp_delete( o, t )  do{ delete ( t *)( o ); }while(0)
#endif


// /
//  definition & include
// /
#include <stdint.h>
#include <atomic> //C++11

// /
//! PImplPrivTemp
/*!
This class is used to declare the PIMPL Private Object.
*/
// /
SCIPACK_NAMESPACE_BEGIN

template <typename T>
class  PImplPrivTemp  {
public:  
// =================================================================
// CTOR/DTOR
// =================================================================
PImplPrivTemp (  ) { m_ref_cntr.store(1); }
virtual ~PImplPrivTemp ( ) { }

// =================================================================
// Functions
// =================================================================
virtual T*    duplicateIfShared ( void ** );

static T*    buildIfNull ( void **w_obj );
static T*    createInstance ( )           { return SCIPACK_PImplPrivTemp_new( T ); }
static T*    createInstance ( void *ref ) { return SCIPACK_PImplPrivTemp_new( T,   *(( T *)( ref )) ); }
static T*    addRef    ( void *cd )       { if ( cd != nullptr ) { (( T *)cd )->addRefCntr( ); } return ( T *)( cd ); }
static bool  releaseRef( void *   );
static bool  attach    ( void **src_obj, void **dst_obj );

protected:
inline int  addRefCntr( )    { return m_ref_cntr.fetch_add(1) + 1; }
inline int  releaseRefCntr( ){ return m_ref_cntr.fetch_sub(1) - 1; }
inline int  currRefCntr( )   { return m_ref_cntr.load(); }

private:
std::atomic<int>  m_ref_cntr;
};

// =====================================================
//! build an instance if the *w_obj is NULL
/*!
@param  w_obj [ in_out ] the object pointer of pointer
@return a object that created or existed.
@note   if *w_obj is null, this routine will create one.
*/
// =====================================================
template <typename T >
T*   PImplPrivTemp<T> :: buildIfNull( void **w_obj )
{
if ( w_obj == nullptr  ) { return nullptr; }
if ( *w_obj == nullptr ) { *w_obj = PImplPrivTemp<T>::createInstance( ); }
return ( T *)( *w_obj );
}

// =====================================================
//! release the reference or delete it if reference counter is zero
/*!
@param cd [ in ] the object pointer
@note  decrease the reference counter, if counter is zero after decreased,\n
this routine will delete the object pointed by cd.
*/
// =====================================================
template <typename T>
bool  PImplPrivTemp<T> :: releaseRef ( void *cd )
{
bool is_released = false;
if ( cd != nullptr ) {
if ( (( T *) cd )->releaseRefCntr( ) == 0 ) {
SCIPACK_PImplPrivTemp_delete( cd, T );
is_released = true;
}
}    
return is_released;
}

// =======================================================
//! duplicate if shared
/*!
@param w_obj [ in_out ] the object pointer of pointer
@return object pointer duplicated or existed
@note  this routine check the reference counter, if it is not one, \n
use copy constructor to duplicate a new one, and return it. NOTE: \n
the *w_obj will be changed if a new object created. \n
User must implement the COPY CONSTRUCTOR if used this function.
*/
// =======================================================
template <typename T >
T *    PImplPrivTemp<T> :: duplicateIfShared( void **w_obj )
{
if ( w_obj == nullptr ) { return nullptr; }
if ( this->currRefCntr( ) == 1 ) { return ( T *)( *w_obj ); }

T *new_obj = PImplPrivTemp<T>::createInstance( *w_obj );
PImplPrivTemp<T>::releaseRef( *w_obj );
*w_obj = new_obj;

return new_obj;

// ===========================================================
//! attach to an existed object
/*!
@param src_obj [ in_out ] the source object pointer of pointer
@param dst_obj [ in     ] the target object pointer of pointer
@return true for attached, false for an error.
@note  this routine make the *src_obj attach to *dst_obj.
*/
// ===========================================================
template <typename T >
bool    PImplPrivTemp<T> :: attach ( void **src_obj, void **dst_obj )
{
// do not attach to self
if ( src_obj == dst_obj ) { return true; }
if ( src_obj == nullptr ) { return false; }

// free self
if ( *src_obj != nullptr ) {
PImplPrivTemp<T>::releaseRef( *src_obj );
*src_obj = nullptr;
}

// attach to dst.
// user maybe use  attach( obj, nullptr ), so check the dst_obj address is needed.
if ( dst_obj > ( void **)( 0x100 ) ) {
if ( *dst_obj != nullptr ) {
*src_obj = PImplPrivTemp<T>::addRef( *dst_obj ); 
}
}

    return true;
}


SCIPACK_NAMESPACE_END

/*!
@}
*/

/*!
@}
*/

/*!
@}
*/


#endif\

\

\

\