わたくしと正反対のポインタ② | ゲームプログラマ志望が福岡で叫ぶ 『絶望』

ゲームプログラマ志望が福岡で叫ぶ 『絶望』

プログラマーになりたい!!!!! あ、風のうわさで聞いた最近若者で流行っているトゥイッターなるものを始めてみました (・ト・) @toshi_desu_yo

ケイン・コスギのようなスマートなポインタ。


スマートポインタの第二幕です(`・ω・´)


なぜケイン・コスギかというと、僕の中で一番好きなコスギが ケイン・コスギ だからです。
『べつにケイン・コスギはスマートじゃない』っていうのは受け付けません。




取り敢えず 前回のスマートポインタ に付け加えたい、無くてはならない機能としては,,,,


 
************************************

・スマートポインタ間のコピー
・アップキャストの対応

************************************



が最低限でしょうか。



スマートポインタ間のコピーは、



SmartPtr< MyClass > spMyClassA( new MyClass );
SmartPtr< MyClass > spMyClassB;

spMyClassB = spMyClassA;




================================================
保持しているポインタの受け渡しと参照カウンタの共有化をさせる。
================================================

ということです。



これは Operator 機能使えば出来そうです。




********【 Operator 】*********


クラスに

void opeartor = ( /* 引数 */ )
{
}



と書けば  『= 関数を作成した』みたいな感じです。

だから関数の中身に自分で好きな記述をすることができます。



使い方としては


class Object
{
public:
    void operator = ( Object* pObj )
    {
        printf( "= 関数が呼ばれたよ。" );
    }

};

~~~~~~~~~~~

Object* pObjectA = new Object;
Object* pObjectB = new Object;

pObjectB = pObjectA;


----【出力】----

"= 関数が呼ばれたよ。"





という感じで、 = の右側に書いた物が引数となります。

べつに Object型のポインタを引数に取らなくても...



class Object
{
public:
    void operator = ( int value )
    {
        printf( "数字は %d です¥n", &value );
    }

};

~~~~~~~~~~~

Object* pObjectA = new Object;

pObjectA = 1;
pObjectA = 3;


----【出力】----

"数字は 1 です"
"数字は 3 です"






と、引数はなんでもいいです。


取り敢えず ”演算子を継承する” と僕は覚えてます。



コレは "==", "+", "-", "->", "/", "*". "<<" など

c++ にある演算子は全部継承できます。



****************************






スマートポインタ間のコピーが出来るように operator = をスマートポインタクラスに記述...



template< class T >
class SmartPtr
{
protected:

/* 内包されるポインタ */
T* mPtr;

/* 参照カウント */
unsigned int* mpCount;

public:

explicit SmartPtr( T* ptr = NULL )
: mPtr( ptr ), mpCount( NULL )
{
if ( mPtr )
{
mpCount = new unsigned int( 1 );
}
}
explicit SmartPtr( SmartPtr< T >& sp )
{
mPtr = sp.mPtr;
mpCount = sp.mpCount;
( *mpCount )++;
}
~SmartPtr()
{
Release();
}


/**
* 内包してあるポインタを渡す
*/
T* GetPtr() const { return mPtr; }


/**
* [ Operator = ]
* スマートポインタ間のコピー
*/
SmartPtr< T >& operator = ( const SmartPtr< T >& sp )
{
//** 同じポインタは代入しない
if ( mPtr != sp.GetPtr() )
{
//** 元々の参照カウンタを減少
Release();

//** 入れ替え
mpCount = sp.mpCount;
mPtr = sp.mPtr;

if ( mpCount != NULL )
++*mpCount;
}

return *this;
}






protected:
void Release()
{
//** 参照カウンタが0になったらdeleteを行う。
if ( mPtr && --*mpCount == 0 )
{
delete mPtr;
delete mpCount;

mPtr = NULL;
mpCount = NULL;
}
}
};



すでに 自分が ポインタを保持している可能性が あるので、まず Release をすることが必須です。

それから入れ替えます。


そして、ポインタを共有する人数が増えたので参照カウンタを増加。。。



こんなかんじで実行。




良い感じ・・・


便利に使いやすくするように operator -> operator * も記述。。。




template< class T >
class SmartPtr
{
protected:

/* 内包されるポインタ */
T* mPtr;

/* 参照カウント */
unsigned int* mpCount;

public:

explicit SmartPtr( T* ptr = NULL )
: mPtr( ptr ), mpCount( NULL )
{
if ( mPtr )
{
mpCount = new unsigned int( 1 );
}
}
explicit SmartPtr( SmartPtr< T >& sp )
{
mPtr = sp.mPtr;
mpCount = sp.mpCount;
( *mpCount )++;
}
~SmartPtr()
{
Release();
}


/**
* 内包してあるポインタを渡す
*/
T* GetPtr() const { return mPtr; }
T* operator -> () const { return GetPtr(); }
T& operator * () const { return *GetPtr(); }


/**
* [ Operator = ]
* スマートポインタ間のコピー
*/
SmartPtr< T >& operator = ( const SmartPtr< T >& sp )
{
//** 同じポインタは代入しない
if ( mPtr != sp.GetPtr() )
{
//** 元々の参照カウンタを減少
Release();

//** 入れ替え
mpCount = sp.mpCount;
mPtr = sp.mPtr;

if ( mpCount != NULL )
++*mpCount;
}

return *this;
}






protected:
void Release()
{
//** 参照カウンタが0になったらdeleteを行う。
if ( mPtr && --*mpCount == 0 )
{
delete mPtr;
delete mpCount;

mPtr = NULL;
mpCount = NULL;
}
}
};




-> *

保持してあるポインタにアクセスできるようになりました!(`・ω・´)



これで使いやすさ UP  ↑





*************************


次に 【 アップキャスト 】




class A
{};

class B : public A
{};


~~~~~~~~~~~~~


SmartPtr< A > A( new B );



SmartPtr< A > A;
SmartPtr< B > B( new B );

A = B;





実現したい。



先ほどのスマートポインタクラスではエラーとなる
ので

新たな コピーコンストラクタ と operator を作成。





template< class T >

class SmartPtr

{

protected:


/* 内包されるポインタ */

T* mPtr;


/* 参照カウント */

unsigned int* mpCount;


public:


explicit SmartPtr( T* ptr = NULL )

: mPtr( ptr ), mpCount( NULL )

{

if ( mPtr )

{

mpCount = new unsigned int( 1 );

}

}

explicit SmartPtr( SmartPtr< T >& sp )

{

mPtr = sp.mPtr;

mpCount = sp.mpCount;

( *mpCount )++;

}

/**

* アップキャスト対応させるコンストラクタ

*/

template< class T2 >

SmartPtr( const SmartPtr< T2 >& sp )

{

mPtr = sp.GetPtr();

mpCount = sp.GetCounter();

++*mpCount;

}

~SmartPtr()

{

Release();

}



/**

* 内包してあるポインタを渡す

*/

T* GetPtr() const { return mPtr; }

T* operator -> () const { return GetPtr(); }

T& operator * () const { return *GetPtr(); }

// 参照カウンタ

unsigned int* GetCounter() const { return mpCount; }



/**

* [ Operator = ]

* スマートポインタ間のコピー

*/

SmartPtr< T >& operator = ( const SmartPtr< T >& sp )

{

if ( mPtr != sp.GetPtr() )

{

Release();


mpCount = sp.mpCount;

mPtr = sp.mPtr;


if ( mpCount != NULL )

++*mpCount;

}


return *this;

}

// アップキャスト対応

template< class T2 >

SmartPtr< T >& operator = ( const SmartPtr< T2 >& sp )

{

if ( mPtr != sp.GetPtr() )

{

Release();


mpCount = sp.GetCounter();

mPtr = sp.GetPtr();


if ( mpCount != NULL )

++*mpCount;

}


return *this;

}







protected:

void Release()

{

//** 参照カウンタが0になったらdeleteを行う。

if ( mPtr && --*mpCount == 0 )

{

delete mPtr;

delete mpCount;


mPtr = NULL;

mpCount = NULL;

}

}

};








template< class T2 >

SmartPtr( const SmartPtr< T2 >& sp )


template< class T2 >

SmartPtr< T >& operator = ( const SmartPtr< T2 >& sp )




これが、アップキャストに対応させたコピーコンストラクタ operator = です。



template はビルド通した時に 


『おい! この記述は出来ねーぞks!!!』

罵倒してくれるので、





キャストがうまくいかない書き方をしていた場合、
実行前にエラーを出してくれます。



すごい・・・便利です・・・///




使ってみた ↓


【 コピーコンストラクタ 】



【 operator = 】




うまくビルドも通ってメモリリークも発生していません!
(゚∀゚≡(゚∀゚≡゚∀゚)≡゚∀゚)



コレを元に自分で機能を追加していってみるといいんじゃないかと思います。




いじょu!


****************************************
【 (URL) スマートポインタ02
****************************************







『iPhone開発の XCode とかは自力でメモリ管理してくれてるからいいなぁ・・・』

と思ってたりもするけどメモリ関係は自分で管理してないと不安で仕方がないと感じる自分もいるので iPhone開発中、実はXCodeのメモリ管理を切ってたりします。


というか、
ちょっと前にやっとObjective-Cをそこそこ使えるようになって、Objective-Cのみでゲーム作ったりした。

それまで C++ で書いてました。


Objective-C 使いやすいとは思うけど独特のメモリ管理がムズムズする。

あと 実機ではOpenGL ES で使えない機能があったりしてめっちゃ困る。


前モデルを3Dで出すアプリ作ってた時、テクスチャに行列書き込みが出来なかった・・

あと、シュミレーターではアンチエイリアス効く所が実機では効かなかった・・・



あ、愚痴になってきたのでココらへんで去ります