new 演算子の処理は自前で定義することでカスタマイズできる。
■ perator newをオーバーライドする
メモリを確保する処理をオーバーライドする。
void *operator new( size_t sz ) {
gCnt ++;
return malloc( sz );
}
POINT
ペアになるように operator delete も定義する。
void operator delete( void *p ) {
gCnt --;
free( p );
}
■ 追加の情報をわたす
operator new() は引数に応じたものが呼ばれる。
最初の size_t 引数は必須の項目。その後は任意。
デバッグ情報をうけとる operator new では 2つの引数を追加する。
operator new( size_t sz, const char *file, int line ) {
}
int *a = new( __FILE__, __LINE__ ) int[4];
メンドイのでマクロにする。
#define NEW new( __FILE__, __LINE__ )
int *a = NEW int[4];
■ mallocする領域に追加する
確保するメモリの前後にマークをつけることでメモリ破壊を検地する。
void *operator new( size_t worksz ) {
int sz = worksz + sizeof( int ) * 4;
char *p = (char *)malloc( sz );
int *pt = (int *)p;
pt[0] = worksz;
pt[1] = 12345678;
pt = p + sizeof( int ) * 2 + worksz;
pt[0] = 12345678;
return p + sizeof(int)*2;
}
■ malloc.のように失敗しても NULL を返さない
// これは OK
void *p = malloc( 1024*1024*1024 );
if ( p == 0 ) {
printf("malloc fail\n");
}
// new は失敗すると Exception をなげる
class Test{
int i;
};
try {
Test *p = new Test[350*1000*1000];
}
// ここで補足しないと
catch(...){
printf("fail new\n");
}
// NULL を返したいなら new(std::nothrow) を利用する
// 過去の互換性をとるための new
int *p = new( std::nothrow ) int[350*1000*1000];
if ( p == NULL ) {
printf( "new fail" );
}
// WARNING
// Exception を投げないのは Memory 確保のときだけ
// その後の ctor で投げられたら OUT
class Test
{
int i;
public:
Test(){
printf("Test ctor\n");
throw( bad_alloc() );
}
};
// Memory 確保に失敗すると NULL をかえす
// 成功すると ctor をよぶ -> ここで Exception を投げられる可能性はある
Test *p = new( std::nothrow ) Test[1*1000*1000];
if ( p == NULL ) {
printf("new fail\n");
}
■ 宣言しなくてもメンバ関数はstatic扱い
DESC
メモリブロックの指定は外からする必要あり
void *operator new( size_t t ) {
// `this' is unavailable for static member functions
// MemBlk を取得する関数に this はない
dpi( this->data );
// この後に constructor が実行される。
return work;
}
POINT
static な GlobalNew は FileScope で利用される
-> ! WARNING がでる. !
LocalDelete() を定義しても, dtor は呼ばれるらしい
[ System ] -> Cls::dtor() -> Cls::operator delete(); という順番らしい.
operator delete() はあくまで, Memory の解放のためにあるようだ.
class Foo
{
public:
~Foo(){ dps("Foo dtor"); }
// うばう. dtor は走る.
void operator delete( void*p ){
printf("operator delete");
}
};
WARNING:
WARNING C4211: 非標準の拡張機能が使用されています :
EXtern が static に再定義されました。
POINT
優先順
Global < FileScopeGlobal < ClassLocal の operator new
実は, new, delete は Memory を確保に失敗すると Exception を投げる
EXception を投げる際も, new, delete が呼ばれる
どこから new, delete をどこから利用しているかわからない.
だから Exception を投げずに, NULL を返す仕様の方がよいかも
Constuctor は new XXX の形でしか呼べない. ?
size_t 以外の OperatorNew ( PlacementNew ) を利用した場合は,
Overload になるのかな ?
-> 隠ぺいされてしまう
-> 隠蔽されない. ! Build できてしまう.
WARNING C4345: 動作変更 :
形式 () の初期化子で構築される POD 型のオブジェクトは [ 既定初期化 ] されます
この WARNING の考察.
次の条件の際におきる.
DefaultCtor 未定義. && Foo() // () ありの ctor ( -> 0 初期化. )
&& PlacementNew の定義.
() なしならば, 0 初期化されない.
SOL
ctor で () をつけない. ( 2 種類ある )
要は
PlacementNew ないで, Object を初期化しても
DefaultCtor で 0 Clear しますよ ! と言っている
POINT
PlacementNew をする場合は, ctor をしっかり定義すること
STL は Cpp の CMP に必ず付属する. ( だから PS3 でもある. )
-> STL の Allocator 指定は,
要は, Memory をここからとってよ ! という意味.
自分の中で, new する場合は,
別途の領域から取得する.
実は operator new は Method なので, OverWrite, OverLoad が可能.
-> public に Access されるので, public にする必要がある.
Class 内で宣言したものは,
要は, Object の生成空間を指定する際に使う.
-> さらに継承されるので, 継承によって, Pool を指定することもできる.
// Memory を指定するための クラスを用意してもいい.
// 継承すれば, OK ! ( MultiInheritance )
//
// MemorySelect を利用したもの同士を継承してしまうと競合がおきる.
//
class MemorySelect {
};
派生先で定義した場合は, OverWrite される.
-> しない場合は, bCls で[ 定義したもの.ま.で ]さかのぼる.
operator new( size_t , ... ) 引数リスト自体を カスタムすること可能
-> 逆に呼び出したい new の Signature にあうように指定する必要あり.
ClassLocalNew を定義した場合は, new Foo; では GlobalNew は見に行かない.
-> このあたりは Scope の解決の問題かも.
operator new ( size_t sz, void *memBlk ) {
...
}
new( gWork ) Array();
Class の外で定義したものは, Global( 誰からも見れる )New, GlobalDelete となり,
new , delete 時に call される.
-> operator new も operator の考えに基づけば, 関数のひとつ.
さらに system の new も malloc() を呼ぶらしい. ?
-> ので自分で NewGbl を overwrite する場合も, malloc 利用して OK
C:\Program Files\Microsoft Visual Studio 8\VC\crt\src\new.cpp
void *__CRTDECL operator new(size_t size) _THROW1(_STD bad_alloc)
{ // try to allocate size bytes
void *p;
// malloc() している.
while ( (p = malloc(size)) == 0 )
if (_callnewh(size) == 0)
{ // report no memory
static const std::bad_alloc nomem;
_RAISE(nomem);
}
return (p);
}
■ 初期化リストは必ず記述
WARNING
仮引数は _data とする
foo()::foo(int _data)
: data(_data)