C++ Primer (第 5 版) 書籍全体の主要な学習ノート

目次

第12章 ダイナミックメモリ

12.1 動的メモリとスマート ポインタ

12.1.6 弱いptr

12.2 動的配列

12.2.1 新しい配列と配列

12.2.2 アロケータ クラス


 

第12章 ダイナミックメモリ

12.1 動的メモリとスマート ポインタ

12.1.6 弱いptr

weak_ptr は、それが指すオブジェクトの有効期間を制御しないスマート ポインターであり、 shared_ptr によって管理されるオブジェクトを指します。弱い ptr をshared_ptrにバインドしても、shared_ptrの参照カウントは変わりません。オブジェクトを指す最後のshared_ptrが破棄されると、オブジェクトは解放されます。

弱い ptr を作成するときは、共有 ptr で初期化します。

auto p = make_shared<int>(42);
weak_ptr<int> wp(p);

オブジェクトが存在しない可能性があるため、weak_ptr を使用してオブジェクトに直接アクセスすることはできませんが、lock を呼び出して、weak_ptr が指すオブジェクトがまだ存在するかどうかを確認する必要があります。存在する場合、lock は共有オブジェクトを指す共有 ptr を返します。

if (shared_ptr<int> np = wp.lock()) { 
    // 只有当1ock调用返回true时我们才会进入if语句体
}

12.2 動的配列

12.2.1 新しい配列と配列

new でオブジェクトの配列を割り当てるには、型名の後に角括弧を付けて、割り当てるオブジェクトの数を指定します。角括弧内のサイズは整数である必要がありますが、定数である必要はありません。

//调用get size确定分配多少个int
int *pia = new int[get size()]; //pia指向第一个int

新しい式で角かっこが不要になるように、配列の型を示す型エイリアスを使用して配列を割り当てることもできます。

typedef int arrT[42];    //arrT表示42个int的数组类型
int *p = new arrT;    //分配一个42个int的数组;p指向第一个int
int *p = new int[42];   //编译器执行这个表达式时还是会用new[]

 typedefの使い方:【C/C++】【typedef】使い方事典_C++におけるtypedefの使い方

new で配列を割り当てると、配列型のオブジェクトではなく、配列要素型のポインタが取得されます。型エイリアスを使用して配列型を定義した場合でも、new は配列型のオブジェクトを割り当てません。上記の例では、 new は要素タイプへのポインターを返します。
割り当てられたメモリは配列型ではないため、動的配列に対して begin または end を呼び出すことはできません。これらの関数は、配列の次元を使用して最初と最後の要素へのポインターを返します。同じ理由で、range for ステートメントを使用して動的配列内の要素を処理することはできません。

動的に割り当てられたオブジェクトの配列を初期化する:デフォルトでは、new によって割り当てられたオブジェクトは、個別に割り当てられているか配列内にあるかに関係なく、デフォルトで初期化されます。配列内の要素は、サイズの後に空の括弧を続けることで値を初期化できます。新しい標準では、要素初期化子の括弧付きリストも提供できます。

int* pia = new int[10];    //10个未初始化的int
int* pia2 = new int[10]();   //10个值初始化为0的int       
    
int* pia3 = new int[10]{ 0,1,2,3,4,5,6,7,8,9 };   //10个1nt分别用列表中对应的初始化器初始化
string* pia4 = new string[10]{ "a","an","the",string(3,'x') };   //10个string,前4个用给定的初始化器初始化,剩余的进行值初始化

空の配列を動的に割り当てることは正当です。newを使用してサイズ 0 の配列を割り当てると、new は正当な null 以外のポインタを返しますが、このポインタは逆参照できません。結局のところ、このポインタはどの要素も指していません。

char arr[0];     // 错误:不能定义长度为0的数组
char* cp = new char[0];      //正确:但cp不能解引用

動的配列の解放:動的配列を解放するには、ポインターの前に空の角括弧のペアを置く特別な形式の削除を使用します。空の角括弧のペアは、配列へのポインターを解放するときに必要です。これは、このポインターがオブジェクトの配列の最初の要素を指すようにコンパイラーに指示します。配列へのポインターを削除するときに角括弧を省略した場合の動作は未定義です。

delete cp;    // p必须指向一个动态分配的对象或为空
delete [] cp;    //pa必须指向一个动态分配的数组或为空

スマート ポインターと動的配列:標準ライブラリには、新しく割り当てられた配列を管理できるバージョンの unique_ptr が提供されています。unique_ptr を使用して動的配列を管理するには
、オブジェクト タイプの後に空の角かっこを続ける必要があります。

一意の ptr が配列を指す場合、ドットと矢印のメンバーシップ演算子は使用できません。結局のところ、一意の ptr は単一のオブジェクトではなく配列を指すため、これらの演算子は無意味です。一意の ptr が配列を指す場合、添え字演算子を使用して配列内の要素にアクセスできます。

// up指向一个包含10个未初始化int的数组	
unique_ptr<int[]> up(new int[10]);
for (size_t i = 0; i != 10; ++i) {
	up[i] = i;
	cout << "up" << "[" << i << "]:" << up[i] << endl;
}
//自动用delete[]销毁其指针
up.release();

unique_ptr とは異なり、shared_ptr は動的配列の管理を直接サポートしません。shared_ptr を使用して動的配列を管理する場合は、独自に定義したデリーターを提供する必要があります。

shared_ptr は添字演算子を定義せず、スマート ポインター タイプはポインター演算をサポートしません。したがって、配列内の要素にアクセスするには、get を使用して組み込みポインターを取得し、それを使用して配列要素にアクセスする必要があります。

 

12.2.2 アロケータ クラス

アロケータ クラス:標準ライブラリのアロケータ クラスはヘッダー ファイル メモリ内で定義されており、オブジェクトの構築からメモリ割り当てを分離するのに役立ちます。これは、未加工で構築されていないメモリを割り当てるための型を認識した方法を提供します。

アロケータ オブジェクトを定義するには、アロケータが割り当てることができるオブジェクトのタイプを指定する必要があります。アロケータ オブジェクトがメモリを割り当てるとき、指定されたオブジェクト タイプに適切なメモリ サイズとアライメントが決定されます。

allocator<string> alloc;    //可以分配string的allocator对象
auto const p = alloc.allocate(8);    //分配n个未初始化的string

アロケータは非構築メモリを割り当てます:アロケータによって割り当てられたメモリは非構築です。必要に応じて、このメモリ内にオブジェクトを構築します。新しい標準ライブラリでは、構築メンバー関数はポインターと 0 個以上の追加引数を受け取り、
指定された位置に要素を構築します。

auto q = p;    // q指向最后构造的元素之后的位置
alloc.construct(q++);    //*q为空字符串
alloc.construct(q++, 10, 'c');    //*q为cccccccccc
alloc.construct(q++, "hi");    //*g为hi!

assign によって返されたメモリを使用するには、construct を使用してオブジェクトを構築する必要があります。非構築メモリの場合、動作は未定義です。

オブジェクトの処理が完了したら、構築された各要素に対して destroy を呼び出してそれらを破棄する必要があります。関数 destroy はポインターを受け取り、指定されたオブジェクトに対してデストラクターを実行します。

while(q!=p)
    alloc.destroy(--q);  //释放我们真正构造的string

ループの開始時に、q は最後に構築された要素の後の位置を指します。destroy を呼び出す前に q をデクリメントしました。したがって、最初に destroy が呼び出されるとき、q は最後に構築された要素を指します。ループの最後のステップで、最初に構築された要素を破棄すると、g は p に等しくなり、ループは終了します。 

メモリの解放は、deallocate を呼び出すことで行われます。

alloc.deallocate(p, n);

未初期化メモリをコピーして埋めるためのアルゴリズム : 標準ライブラリでは、初期化されていないメモリにオブジェクトを作成できるアロケータ クラス用の 2 つのコンパニオン アルゴリズムも定義されており、どちらもヘッダー ファイル メモリで定義されています。

初期化されていないコピー(b,e,b2) 反復子 b および e が指す入力範囲の要素を、反復子 b2 で指定された未構築の生メモリにコピーします。b2 が指すメモリは、入力シーケンス内の要素のコピーを保持するのに十分な大きさでなければなりません。
uninitialized_copy_n(b,n,b2) イテレータ b が指す要素から開始して、b2 から始まる n 個の要素をメモリにコピーします。
uninitialized_fill(b,e,t) イテレータ b と e で指定された元のメモリ範囲にオブジェクトを作成します。オブジェクトの値は t のコピーです。
uninitialized_fill_n(b,n,t) b. イテレータが指すメモリ アドレスから始まる n 個のオブジェクトを作成します。b は、指定された数のオブジェクトを保持するのに十分な大きさの未構築の生メモリを指す必要があります。

おすすめ

転載: blog.csdn.net/qq_41921826/article/details/132004307