C#などの管理言語からC++にアプローチしているようです。C++では状況が少し異なります。
参照型として説明するものは、C++には存在しません。C ++の型は、「参照型」でも「値型」でもありません。それらは単なる「タイプ」です。それらが参照(またはポインター)を介して処理されるか、値によって処理されるかは、型を使用するコード(型の定義ではない)に完全に依存します。対照的に、C#のような言語では、型宣言者は型を参照として処理するか値として処理する必要があるかを決定します。C ++には参照と呼ばれるものがありますが、それはあなたが説明することとは何の関係もありません。最後にC++リファレンスについて説明します。
それでは、質問のいくつかの部分を処理できるかどうかを見てみましょう。
ポインターがスタックに置かれ、ポインターが指す実際のデータが作成され、ヒープに配置されます。
多分。これは、次のようなオブジェクトを作成する場合に当てはまります。たとえば、次のようになります。
class MyClass { /* ... */ };
...
MyClass* pObj1 = new MyClass();
MyClass* pObj2 = (MyClass*)malloc( sizeof(MyClass) );
ただし、次のようなオブジェクトを作成する場合はそうではありません。
MyClass obj3;
後者の場合、オブジェクトはスタックに割り当てられ、ポインターや参照は含まれません。'値型'として操作しています。
MyClass *pObj3 = &obj3;
pObj3
これは、(スタック内の)へのポインタでありobj3
、これもスタック内にあります。見る?クラス定義とそのクラスのオブジェクトが格納されている場所との間に関係はありません。タイプの使い方によって異なります。同じタイプのスタックベースのオブジェクトとヒープベースのオブジェクトの両方を組み合わせるのはかなり一般的です。
標準配列とユーザー定義クラスは参照型です。これは正しいです?
いいえ; 配列は、連続するメモリ位置に配置された同じタイプ/サイズのオブジェクトのセットです。配列は、個々のオブジェクトの場合と同様に、スタックまたはヒープに割り当てることができます。
CおよびC++は、配列に明確なセマンティクスを配置しません(1つの例外を除いて、後で説明します)。それらが割り当てられると、それらはたまたま連続しているオブジェクトの集まりにすぎません。配列操作またはダイレクトポインタ操作を使用して個々のメンバーにアクセスするかどうかは、プログラム次第です。つまり、次のことを意味します。
arrayOfClass[i]
と言うのとまったく同じです((Class*)*(array + i))
。Cでは、と言うこともできます。i[arrayOfClass]
これは、と同じ意味arrayOfClass[i]
です(ただし、C ++は、より厳密な型規則があるため、文句を言います)。
- 配列の一部ではない(そしてクラッシュする可能性が高い)オブジェクトへのポインターで配列演算子を使用できます
- 配列上の要素に対して通常のポインタ操作を使用できます。
- 小さなオブジェクトの配列のメンバーであるかのように、そのメモリの小さな連続した部分を解釈することで、「大きな」メモリのチャンクを割り当て、「独自の配列を作成」できます(これは、malloc()を使用したときに得られるものです)。
配列はそれ自体が型ではありません。これらは、複数のオブジェクトを割り当てるための便利な方法であり、状況によってはより便利なポインタを実行するための方法です。
この「配列は特別ではない」という規則で頭に浮かぶ唯一の例外は、C++で。を介して配列が割り当てられる場合new
です。を介して配列を割り当てると、配列new
が割り当てられたときに含まれていた要素の数に関する情報(通常は配列に隣接するヒープにありますが、必須ではありません)が残ります。次に、特別なdelete []
演算子を使用して配列を削除する必要があります。delete []
その余分な情報を見つけて使用し、配列のすべての要素を正しく削除します。
次に、私の主な質問は、cおよびc ++のメモリ管理メカニズム(malloc、freeおよびnew、delete)が常にこれを適切に処理し、クラスまたは配列が指しているメモリを解放するかどうかです。
あなたが物事を正しく行う限り、そうです。
それらのポインターがヒープ上の同じサイズ/タイプの他のオブジェクトに何らかの方法で再割り当てされた場合でも、すべてが機能しますか?
はいfree()
。ただし、free()()以外を呼び出すときに別の型へのポインタを使用することvoid*
は、かなり珍しいことです。そのようなものの合法的な使用法がありますが、それらは高度なトピックです。経験豊富な開発者にデザインを見てもらい、それが本当に適切なことかどうかを確認することをお勧めします。
delete
別の問題です。deleteを呼び出したときにバッファに格納されていたものとは異なる型へのポインタを使用すると、動作は「未定義」になります(つまり、クラッシュする可能性があります)。それdelete
は、何よりも多くのことをfree()
行うからです。また、オブジェクトのデストラクタメソッドを呼び出し、コンパイラはポインタの型に依存して適切なメソッドを呼び出します。間違ったポインタタイプを使用すると、間違ったメソッドが呼び出され、誰が何が起こるかを知っています。何か「他の」ものをバッファに入れた後、それをバッファに入れる可能性がnew
ありますが、それは取るに足らない量の作業を必要とする可能性があり、これも高度なトピックです。
また、で割り当てて解放することは絶対にしないでください。また、で割り当ててmalloc()
解放することdelete
もできません。メソッドが適切にペアになっていることを確認してください。new
free()
クラスに別のオブジェクトを指すポインタメンバーがある場合はどうなりますか?クラスオブジェクトを削除/解放しても、そのメンバーポインタが指しているものは解放されないと思いますが、それは正しいですか?
C ++では、これに対処するための標準的な方法は、クラスにデストラクタが必要であり、デストラクタがポインタメンバーの解放を処理することです。Cでは、選択の余地がなく、外部ポインターをクリアする前に、ポインターメンバーを手動でクリアする必要があります。
これはすべて、オブジェクトがメンバーポインタが指すコンテンツを所有していることを前提としています。C#のような管理された言語では、すべてのオブジェクトはランタイムによって「所有」され、ガベージコレクターの制御下で削除されるため、心配する必要はありません。C++の場合。メンバーポイントによってポイントされるオブジェクトを「所有する」人は、言語ではなくプログラムのセマンティクスによって定義されます。埋め込みオブジェクトを削除する適切なタイミングを決定するために注意を払う必要があります。オブジェクトを削除する適切なタイミングを逃すと、メモリがリークします。削除するのが早すぎると、未定義の動作が発生してクラッシュします(一部のコードがすでに削除されたオブジェクトを使用しようとした場合)。
現在、C ++参照は基本的に、特定の種類のポインターを使いやすくすることを目的とした、少し砂糖を塗った単なるポインターです。原則として、ポインタを使用するだけではC++では実行できない参照で実行できることはほとんどありません。いくつかの例外は、スキップする高度なトピックです(トピックを正義にするために検索する必要があり、リソースが手元にありません)。
あなたの視点では、C++参照はスタックオブジェクトのように見える単なるポインタです。
CMyClass pObj1 = new CMyClass();
CMyClass& myObject = pObj1; // Create a reference to the object pointed by pObj1
pObj1->Method1(); // Use the pointer to call Method1
pObj1.Method1(); // Use the reference to call Method1
あなたのC++の知識のレベルを考えると、C / C ++のメモリ管理をもう少しよく理解するようになるまで、私は今のところ参照から離れているかもしれません。