C ++:callocのように動作する新しい呼び出し?
-
03-07-2019 - |
質問
new
のようにメモリをゼロにするためにcalloc
を呼び出すことができますか?
解決
回答の中で一部の人が言っていることに反して、それは 可能です。
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のように動作する新しいバージョンを作成するのはかなり簡単です。 newのno-throwバージョンが実装されるのとほぼ同じ方法で実行できます。
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();
さらに、define new []のような他の楽しいことも行う必要がありますが、これもかなり簡単です。
いいえ。また、次のようなことも考えないでください。
YourClass *var = new YourClass;
memset(var, 0, sizeof(YourClass));
VTABLEを破棄する可能性があります(クラスにある場合)。
コンストラクタを使用して、クラスの内部メモリ(変数)をクリアすることをお勧めします。
いいえ。割り当てられたアイテムは常にデフォルトで初期化されますが、プリミティブの場合は何もしません。 std :: uninitialized_fill_nの呼び出しなどでフォローアップする必要があります。
演算子new
のグローバルオーバーロードを実行し、calloc()
から生メモリを取得させることができます。これにより、コンストラクターが実行される前にメモリが消去されるため、問題はありません。
独自にnewをオーバーライドするクラスは、特別なdelete
ベースのnew_handler
を取得しませんが、そのクラスはとにかくそれ自体を正しく初期化する必要があります。
bad_alloc
およびno_throw
と配列バージョンの両方をオーバーライドすることを忘れないでください...
次のようなもの:
#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);
}
これらの単純なバージョンは、正確には正確ではありません-<=>演算子は、<=>(インストールされている場合)を呼び出すループで実行し、<=>例外がある場合にのみスローする必要があります<=>なし。または、そのようなものを調べて、後で更新する必要があります。
ああ、<=>バージョンもオーバーライドしたいかもしれません。
iマクロを使用します:
#define newclear(TYPE) new(calloc(sizeof(TYPE), 1)) TYPE();
使用するには:
Whatever* myWhatever = newclear(Whatever);
(これは<!> quot; placement new <!> quotを使用します;他のいくつかのソリューションと同様)
いいえ。手動でメモリをゼロにする必要があります。 new
はメモリの割り当てだけでなく、コンストラクターを介した初期化についても覚えておいてください。これは、Cでcalloc
が便利な場所です(初期化関数はありません)。 <=>にラッパーを自由に書くことも、<=>を使用することもできますが、ほとんどの場合、POD以外のオブジェクトではあまり意味がありません。
new
を使用しない場合は、vector:vector<char> buffer; buffer.resize(newsize);
を使用するだけで、コンテンツはゼロになります。
class MyClass {
public:
void* operator new(size_t bytes) {
return calloc(bytes, 1);
}
}
また、必要に応じてグローバルnew演算子をオーバーライドできます。
言うことができます:
vector <char> v( 100, 0 );
newを使用して100文字の連続した配列を作成し、それらをすべてゼロに初期化します。その後、ベクトルの[]演算子を使用するか、次の操作を実行して配列にアクセスできます。
char * p = &v[0];
p[3] = 42;
これにより、deleteを呼び出して割り当てられたメモリを解放する必要もなくなります。
はい。
int* p_scalar = new int(5);//Does not create 5 elements, but initializes to 5
配列には、memsetのようなものを使用できます。 Windowsの場合、ZeroMemoryまたはSecureZeroMemoryを使用します。
編集: @litbの投稿をご覧ください。彼は、上記のような非直接初期化を使用して配列を0に初期化する方法を示しています。