直接上代码
//这里是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