8

私はまだかなり初心者のプログラマーであり、参照タイプを使用したc++メモリ管理について質問があります。

まず第一に、参照型についての私の理解:

ポインターがスタックに置かれ、ポインターが指す実際のデータが作成され、ヒープに配置されます。標準配列とユーザー定義クラスは参照型です。これは正しいです?次に、私の主な質問は、cおよびc ++のメモリ管理メカニズム(malloc、freeおよびnew、delete)が常にこれを適切に処理し、クラスまたは配列が指しているメモリを解放するかどうかです。それらのポインターがヒープ上の同じサイズ/タイプの他のオブジェクトに何らかの方法で再割り当てされた場合でも、すべてが機能しますか?クラスに別のオブジェクトを指すポインタメンバーがある場合はどうなりますか?クラスオブジェクトを削除/解放しても、そのメンバーポインタが指しているものは解放されないと思いますが、それは正しいですか?

皆さんありがとう!

-R

4

6 に答える 6

19

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もできません。メソッドが適切にペアになっていることを確認してください。newfree()

クラスに別のオブジェクトを指すポインタメンバーがある場合はどうなりますか?クラスオブジェクトを削除/解放しても、そのメンバーポインタが指しているものは解放されないと思いますが、それは正しいですか?

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 ++のメモリ管理をもう少しよく理解するようになるまで、私は今のところ参照から離れているかもしれません。

于 2011-01-18T03:04:48.010 に答える
3

クラスオブジェクトを削除/解放しても、そのメンバーポインタが指しているものは解放されないと思いますが、それは正しいですか?

これはデフォルトで正しいので、C++クラスにはデストラクタがあります。例えば:

class C {
    int* x;

public:
    C () : x (new int[10]) {}  // constructor
};

C* cptr = new C;  // a pointer to a C object

を削除すると、が解放されないcptrため、メモリリークが発生します。xだから私はデストラクタを追加しCます:

class C {
    ...
    ~C () {delete [] x;}  // destructor
};

(残りの質問にはたくさんの問題があります。JavaとC ++を混同しているようです。そのため、ほとんどの質問は意味がありません。このフラグメントのみに回答して、方法の例を示します。リソースを自動的に解放します。言語をよりよく理解するために、C ++の本を読むことをお勧めします。)

于 2011-01-18T02:31:02.440 に答える
2

どこから始めたらいいのかわからない。

プリミティブ型(intなど)があります。

旧友のc構造体があります。

クラスがあります。

これらはすべて、ストレージクラスを自動化できます。スタックに座っているだけです。すべて値で渡すことができます。

次に、xへのポインタがあります。(x *)。これらは、スタック上のアイテムのアドレスを格納するか、。のように別の場所に割り当てられますnew。ポインタを取得したら、それを無効にするようなことをしないようにするのはあなた次第です。関数から戻ると、動的コンテキスト内の自動アイテムへのポインターは無効になります。を使用するdeleteと、削除したポインタは無効になります。もちろん、そのコピーも無効になります。

そして最後に、参考文献があります。x&は単なる構文糖衣です。何かへの参照を渡すことは、それへのポインタを渡すことです。参照型を使用すると、一部の*文字を入力する必要がなくなり、テーブルの下のポインターがnullになることはないと断言されます。

于 2011-01-18T02:14:56.163 に答える
2

ポインターがスタックに置かれ、ポインターが指す実際のデータが作成され、ヒープに配置されます。

ポインタは、別の変数のアドレスを格納する変数です。はい、これが当てはまる可能性があります。ポインターは、常にローカルスコープ(またはスタック)またはフリーストア(ヒープ)を指すことができます。

例 :

class Foo{
    public:
    // For Test1 This is in the Stack
    // For Test2 this is in the free store
    int x; 

    // For Test1 the pointer is in the Stack
    // AND -> It points, to where we set it (could be stack or heap)
    // For Test2 the pointer-variable-location is in the Free Store
    // AND -> Similar
    int *y;
}

int main()
{
    // Lies in the Local Scope
    Foo Test1;
    // Test2 Lies in the Local Scope, and contains the address of the 
    // Object, which is now on the Free Store
    Foo *Test2 = new Foo();
}

私の主な質問は、cおよびc ++のメモリ管理メカニズム(malloc、freeおよびnew、delete)が常にこれを適切に処理し、クラスまたは配列が指しているメモリを解放するかどうかです。

まず第一に、フリーと削除を混ぜないようにしてください。次に、free()ポインタを取得し、提供されたポインタが有効なメモリ位置を指しているかどうかをチェックしません。これは、セグメンテーション違反を引き起こす可能性のある、割り当てられていないメモリを解放しようとする可能性があることを意味します。この標準的な例は

int main()
{
     int * x; // Points to random
     free(x); // Undefined behaviour
}

ポインタの別の間違った使用法は次のとおりです。

int main()
{
     int * x = malloc(sizeof(int) * 10); //Allocate an array of 10
     ++x; // Now points to x[1];
     free(x); // Give me trouble
}

それらのポインターがヒープ上の同じサイズ/タイプの他のオブジェクトに何らかの方法で再割り当てされた場合でも、すべてが機能しますか?

はい、物事は機能し続けることができますが、これはメモリリークを引き起こす可能性があります。古いものを削除する限り、これは問題ありません。

クラスに別のオブジェクトを指すポインタメンバーがある場合はどうなりますか?クラスオブジェクトを削除/解放しても、そのメンバーポインタが指しているものは解放されないと思いますが、それは正しいですか?

free()クラスを実行してもデストラクタは呼び出されず、デストラクタを使用してメモリリークを回避できます。を使用deleteすると、他のオブジェクトを削除するようにデストラクタを設定できます。そうしないと、メモリリークが発生します。

あなたの投稿は、あなたがいくつかのことを混乱させていると私に言っています、あなたはC ++の参照について話し始めますが、ポインタとfree()andについて話しdelete、一般的にあなたが混乱しているという印象を与えます。私はあなたが良い本を手に入れるべきだと思います。

于 2011-01-18T02:16:30.013 に答える
1

クラスは必ずしも参照型ではありません。たとえば、次のコードがある場合:

class dog {
    int age;
    char *name;
};

int main() {
    int x;
    dog barry;
    ...
}

次に、メインの内側で、バリーとxがスタック上で隣り合っています。したがって、スタックには2つの整数とcharへのポインターが含まれます。

オブジェクトを解放しても、そのメンバーポインタが行うメモリは解放されないと言っているのは正しいことです。C ++は自動メモリ管理を行わないため、すべてを手動で割り当てて解放する必要があります。この場合、犬にデストラクタを与えるのが最善です。

class dog {
    ~dog() {
        delete name;
    }
}

〜dogは、犬を削除したとき、または犬がスコープから外れてスタックから外されたときに呼び出されます。

于 2011-01-18T02:17:26.013 に答える
0

参照は基本的に、自動変数の構文を使用する定数ポインターです。それが指すものを変更したり、オブジェクトを削除するために使用したりすることはできません(直接、参照でアドレス演算子を使用して、参照されたオブジェクトへのポインターを取得し、それを削除できます)。

関数mallocfreeメモリのブロックを割り当てて解放するだけです。通常、これらをC++で直接使用する必要はありません。演算子はメモリnewdelete割り当てて解放しますが、オブジェクトのコンストラクタとデストラクタも呼び出します。クラスのコンストラクターでは、すべての自動メンバーのコンストラクターが呼び出され、デストラクタと同じです。クラスにポインタであるメンバーがある場合、そのメモリは自動的に割り当てられたり解放されたりしません。コンストラクタとデストラクタで明示的に行うか、std::auto_ptrのようなスマートポインタを使用する必要があります。

演算子がdeleteポインタで使用されると、ポインタ型のデストラクタが呼び出されるため、明示的なキャストを使用してポインタが間違った型を指すように強制すると、削除時に間違ったデストラクタが呼び出されます。

于 2011-01-18T02:18:32.980 に答える