pImpl的高级用法

直接上代码

//这里是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





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
pimpl(Pointer to Implementation)是一种设计模式,用于隐藏类的实现细节。该模式的主要目的是将类的接口和实现分离,以便提高代码的可维护性和可扩展性。 在传统的C++开发中,类的实现细节通常会暴露在类的头文件中,这样会导致头文件的内容变得庞大且混乱。而pimpl模式通过在类中使用指向实现类的指针,将实现细节脱离类的接口部分,使得头文件只需包含一个简单的指针声明,从而实现了隐藏指针的效果。 使用pimpl模式隐藏指针有多个好处。首先,它可以提高编译速度,因为只有头文件的改变才会导致需要重新编译的文件数量减少;其次,它可以减少对外部用户的依赖,当类的实现发生变化时,只需要重新编译实现文件而无需重新编译使用该类的其他文件;此外,pimpl模式还可以提高二进制兼容性,因为只有指针的大小发生变化,而不是整个类的大小。 使用pimpl模式时,首先需要在类的头文件中声明一个指向实现类的指针,并在类的实现文件中定义实现类。然后,在类的构造函数和析构函数中创建和销毁实现类的对象,并在类的成员函数中通过指针访问实现类的成员。 因此,pimpl模式允许将实现细节从类的接口中分离出来,提高了代码的可维护性和可扩展性。使用pimpl隐藏指针的设计模式可以提高编译速度、减少对外部用户的依赖以及提高二进制兼容性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

vqt5_qt6

你的鼓励是我们创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值