web-dev-qa-db-ja.com

C ++:callocのように動作する新しい呼び出し?

newのようにメモリをゼロにするために、callocに呼び出すことができますか?

38
nivnad

一部の人が答えで言っていることに反して、それはis可能です。

char * c = new char[N]();

すべての文字をゼロで初期化します(実際には、値の初期化と呼ばれます。ただし、値の初期化は、スカラー型の配列のすべてのメンバーに対してゼロで初期化されます)。それがあなたが求めているものなら。

ユーザーがコンストラクターを宣言していないクラス型(の配列)に対しても機能することに注意してください。この場合、それらのメンバーは値で初期化されます。

struct T { int a; };
T *t = new T[1]();
assert(t[0].a == 0);
delete[] t;

それは何らかの拡張などではありません。 C++ 98でも同じように機能し、動作しました。そこでは、値の初期化ではなく、デフォルトの初期化と呼ばれていました。ただし、ゼロ初期化は、スカラーまたはスカラーまたはPODタイプの配列の両方の場合に実行されます。

いいえ。ただし、callocのように機能する新しいバージョンを作成するのはかなり簡単です。これは、no-throwバージョンのnewが実装されているのとほぼ同じ方法で実行できます。

SomeFile.h

struct zeromemory_t{};
extern const zeromemory_t zeromemory;
void* __cdcel operator new(size_t cbSize, const zeromemory_t&);

SomeFile.cpp

const zeromemory_t zeromemory;

void* _cdecl operator new(size_t cbSize, const zeromemory_t&)
{
    void *mem = ::operator new(cbSize);
    memset(mem,0,cbSize);
    return mem;
}

これで、次の操作を実行して、ゼロのメモリで新しいものを取得できます。

MyType* pMyType = new (zeromemory) MyType();

さらに、new []を定義するなど、他の楽しいことも行う必要があります。これもかなり簡単です。

11
JaredPar

いいえ。また、次のようなことも考えないでください。

YourClass *var = new YourClass;
memset(var, 0, sizeof(YourClass));

最終的にVTABLEを破棄する可能性があります(クラスにVTABLEがある場合)。

コンストラクターを使用して、クラスの内部メモリ(変数)をクリアすることをお勧めします。

4

いいえ。割り当てられたアイテムを常にデフォルトで初期化しますが、プリミティブの場合は何もしません。 std :: uninitialized_fill_n呼び出しなどでフォローアップする必要があります。

2
Promit

演算子newのグローバルなオーバーロードを実行し、calloc()から生のメモリを取得することができます。このようにして、コンストラクターが実行される前にメモリがワイプされるため、問題は発生しません。

Newを単独でオーバーライドするクラスは、特別なcalloc()ベースのnewを取得しませんが、そのクラスはとにかく正しく初期化されているはずです。

newdeleteの両方とアレイバージョンをオーバーライドすることを忘れないでください...

何かのようなもの:

#include <exception> // for std::bad_alloc
#include <new>
#include <stdlib.h> // for calloc() and free()

void* operator new (size_t size)
{
 void *p=calloc(size, 1); 
 if (p==0) // did allocation succeed?
  throw std::bad_alloc(); 
 return p;
}


void operator delete (void *p)
{
 free(p); 
}

void* operator new[] (size_t size)
{
 void *p=calloc(size, 1); 
 if (p==0) // did allocation succeed?
  throw std::bad_alloc();
 return p;
}

void operator delete[] (void *p)
{
 free(p); 
}

これらの単純なバージョンは、本来あるべき姿とは完全に一致しないことに注意してください。new演算子は、new_handler(インストールされている場合)を呼び出し、bad_allocのみをスローするループで実行する必要があります。 new_handlerがない場合の例外。またはそのようなもの、私はそれを調べて後で更新する必要があります。

ああ、no_throwバージョンもオーバーライドすることをお勧めします。

2
Michael Burr

私はマクロを使用します:

#define newclear(TYPE) new(calloc(sizeof(TYPE), 1)) TYPE();

それを使用するには:

Whatever* myWhatever = newclear(Whatever);

(これは、他のいくつかのソリューションと同様に「新しい配置」を使用します)

1

いいえ。メモリを手動でゼロにする必要があります。 newは、メモリを割り当てるだけでなく、コンストラクタを介して初期化することでもあることを忘れないでください。これは、C(初期化関数がない)でcallocが便利な場所です。 newのラッパーを自由に記述したり、callocを使用したりすることもできますが、POD以外のオブジェクトの場合、ほとんどの場合、これはあまり意味がありません。

0
dirkgently

newの使用を主張しない場合は、vector:vector<char> buffer; buffer.resize(newsize);を使用するだけで、コンテンツはゼロになります。

0
Francis

はい。

int* p_scalar = new int(5);//Does not create 5 elements, but initializes to 5

配列の場合、memsetのようなものを使用できます。 Windowsの場合は、ZeroMemoryまたはSecureZeroMemoryを使用します。

編集: @ litbの投稿を参照してください。彼は、上記のような非直接初期化を使用して配列を0に初期化する方法を示しています。

0
Brian R. Bondy
class MyClass {
    public:
    void* operator new(size_t bytes) {
        return calloc(bytes, 1);
    }
}

また、必要に応じて、グローバルなnew演算子をオーバーライドできます。

0
Unknown

あなたは言うことができます:

vector <char> v( 100, 0 );

これは、newを使用して100文字の連続した配列を作成し、それらをすべてゼロに初期化します。次に、ベクトルの[]演算子を使用するか、次のようにして配列にアクセスできます。

char * p = &v[0];
p[3] = 42;

これにより、割り当てられたメモリを解放するためにdeleteを呼び出す必要もなくなります。

0
anon