new
メモリの割り当てとコンストラクターの呼び出し以外にオペレーターが行うことは何ですか?
3 に答える
<new>
C++ 標準では、ヘッダーからの new 演算子の単一オブジェクト形式 (通常使用される形式) について次のように述べています。
必要な動作:
適切にアラインされたストレージ (3.7.3) への非 null ポインターを返すか、bad_alloc 例外をスローします。この要件は、この機能の代替バージョンを拘束します。
デフォルトの動作:
— ループの実行: ループ内で、関数は最初に要求されたストレージの割り当てを試みます。この試みが標準 C ライブラリ関数 malloc の呼び出しを伴うかどうかは未規定です。
— 試行が成功した場合、割り当てられたストレージへのポインタを返します。それ以外の場合、set_new_handler() への最後の引数がヌル ポインターであった場合は、bad_alloc をスローします。
— それ以外の場合、関数は現在の new_handler (18.4.2.2) を呼び出します。呼び出された関数が戻ると、ループが繰り返されます。
— ループは、要求されたストレージの割り当てが成功した場合、または呼び出された new_handler 関数が返されなかった場合に終了します。
標準には、 new 演算子と動的メモリ割り当てについて他にも言いたいことがたくさんあります (言いたいことはたくさんあります) が、「デフォルトの動作」リストは new 演算子の基本をかなりうまくまとめていると思います。
私はそれがこの答えで何をするかについての説明を書きました。それはどのように説明します
new
メモリを取得しますnew
メモリ障害を処理しますnew
コンストラクターの例外を処理しますnew
特別な配置とnothrowバージョンを処理します
Michaelは、デフォルトのアロケータ関数(:: operator new)がメモリを適切に取得する方法と、障害を処理する方法について説明しました。オブジェクトのサイズが彼のコメントのどこに保存されているかについてのあなたの質問を見ました。答えは、必要がなければサイズは保存されないということです。Cは次のサイズを必要としないことに注意してくださいfree
(そして:: operator newは単に使用できますmalloc
):
void * memory = malloc(x);
free (memory); // no need to tell it the size
これは、サイズの格納が新しい式の配列形式の割り当てのサイズにどのように影響するかを確認する例です(他の回答ではカバーされていません)。
#include <cstddef>
#include <iostream>
struct f {
// requests allocation of t bytes
void * operator new[](std::size_t t) throw() {
void *p = ::operator new[](t);
std::cout << "new p: " << p << std::endl;
std::cout << "new size: " << t << std::endl;
return p;
}
// requests deleting of t bytes starting at p
void operator delete[](void *p, std::size_t t) throw() {
std::cout << "delete p: " << p << std::endl;
std::cout << "size : " << t << std::endl;
return ::operator delete[](p);
}
};
int main() {
std::cout << "sizeof f: " << sizeof (f) << std::endl;
f * f_ = new f[1];
std::cout << "&f_ : " << f_ << std::endl;
delete[] f_;
}
次のように出力されます。
sizeof f: 1
new p: 0x93fe008
new size: 5
&f_ : 0x93fe00c
delete p: 0x93fe008
size : 5
オブジェクト自体に1バイト、オブジェクトの割り当てられた領域の直前に格納されるカウントに4バイト。ここで、サイズパラメータなしで割り当て解除関数を使用すると(演算子deleteから削除するだけで)、次の出力が得られます。
sizeof f: 1
new p: 0x9451008
new size: 1
&f_ : 0x9451008
delete p: 0x9451008
ここでのC++ランタイムはサイズを気にしないので、それをもう保存しません。これは実装固有のものであり、gccがメンバー演算子deleteのサイズを通知できるようにするためにここで行うことに注意してください。他の実装でもサイズが保存される可能性があり、クラスに対して呼び出すデストラクタがある場合に最も可能性が高くなります。たとえば、~f() { }
上記を追加するだけで、作成する割り当て解除関数に関係なく、gccがサイズを格納します。
オーバーロードされているかどうか、デバッグ用にアプリをビルドしたかどうか、メモリ リーク検出器を使用しているかどうか、ある種のメモリ プール スキームがあるかどうか、ビットをマーク/マーク解除する Boehm ガベージ コレクタのようなものがあるかどうかによって異なります。 、などなど。内部で多くのカスタムを行っているか、特別なことを何もしていない可能性があります。