0


私は C++ ポインターに問題があります

私は C# と VB.NET のプログラマーですが、最近 C++ に変換したので、どういうわけか C++ の新しい初心者

です 今、私は字幕エディターを書いていて、字幕の 2 つのクラスがありますすべての行へのポインターのリストを含む段落クラス

および親段落へのポインターを含む字幕行クラス (行が変更されたときに親のメソッドを呼び出すため)


サブタイトルの段落クラスで、サブ行へのポインターのリストを削除しても削除されない


ポインターを削除した後にポインターを使用していくつかの関数を呼び出すことでこれをテストしましたが、それらは機能します!

また、Ubuntu で「システム モニター」を使用して、ポインターにスペースを割り当てる前後にアプリケーションが使用するメモリの量を確認しました。メモリを割り当てた後に増加することがわかりましたが、ポインターを削除した後にスペースが解放されません。


そこで、いくつか質問があります
。1- それぞれが相互に参照する 2 つのクラスを作成できますか?
2- 2 つのクラスのいずれかのポインターを参照に置き換えると、同じ問題がまだ存在します
3- それぞれが相互に参照している 2 つのクラスがある場合、この参照を手動で解除するにはどうすればよいですか


共有ポインターまたは弱いポインター クラスを使用できることはわかっていますが、最初は手動で行いたいと考えています。


これは、アプリケーションの問題を示すための 2 つのクラスのサンプルです。

#include <iostream>
#include <stdio.h>

class B;

class A
{
    public :
      void setB(B *b){_b = b;cout << "set B" << endl;}
      ~A();
    private:
    B *_b;

};
class B
{
    public :
        void setA(A *a){_a = a;cout << "set A" << endl;}
        ~B(){cout <<"B is dieing" << endl;/*delete _a;*/}
    private:
        A *_a;

};

A::~A(){cout << "A is dieing" << endl;delete _b;}

int main()
{
    getchar(); // two have some time to know how much memory does my application use before allocaing space for pointers

    A *a = new A;
    B *b = new B;

    a->setB(b);
    b->setA(a);

    getchar();// two have some time to know how much memory does my application use after deallocaing the space

    delete a;
    delete b;

    // but here,after deleting it, it's still there, not deleted! I can use it
    a->setB(b);

    getchar();
    return 0;
}

前もって感謝します

ヤセル・ソビー

4

3 に答える 3

3

「それぞれが相互に参照する 2 つのクラスを作成できますか?」という質問に答えると、答えは明らかに「はい」です。ただし、「メモリの所有者は誰か? このポインターはいつ有効なのか? いつ無効なのか? 変更されたかどうか、いつ変更されたかを知るにはどうすればよいか?」について常に考える必要があります。

C# では、.Net フレームワークに組み込まれた参照カウントとガベージ コレクターがメモリの所有権と管理を処理し、適切なタイミングで適切なことを自動的に実行するため、気にする必要はありませんでした。C++ では、そのようなことを考えるのはプログラマーの責任です。

C++ でうまく機能するのは、オブジェクトを所有するコンテキスト内のスタックにオブジェクトを割り当てることです。

int main()
{
    A a;
    B b;

    a.setB(&b);
    b.setA(&a);

    return(0);
}

これで、main() がスコープ外になると、a と b の両方が自動的に破棄されます。

これは、自分で作成した実際の問題にまだ出くわす可能性があります。A クラスは本当に B へのポインターのコピーを保持する必要があるのでしょうか? 多くの場合、A は特定のメソッドの実行中に B への参照のみを必要とします。コピーを保持する代わりに、必要なときに渡してはどうでしょうか。

a.doesSomethingWithB(parm1, parm2, &b);

そうすれば、A は B との長期的なコミットメントを持ちません。

何かのコピーを保持するということは、コピーが本物と同期しなくなる可能性があることを意味します。これが、「Don't Repeat Yourself」ルール (別名 DRY、別名 One Definition Rule) がある理由です。

C++ コードをレビューするとき、「new」演算子のインスタンスを探します。これは、開発者がメモリを手動で管理しようとしていることがわかります。これは、開発者がデストラクタ、ポインタ、コピーに特に注意する必要があることを意味します。ポインターの管理、ライフタイムの管理、コードをより複雑にするこれらすべての余分なもの。複雑なコードはバグにつながります。

于 2013-01-08T15:06:30.177 に答える
1

オブジェクトを削除した後、ポインターが NULL を指すようにすると、両方を使用できなくなります。

ヒープ内のメモリ領域を解放すると、ブロックは空きと見なされるため、それ以降のメモリ割り当てで上書きされます。ただし、そうでない場合でも、見たとおりに使用できます。しかし、それは明らかに良い習慣ではありません。

于 2013-01-08T14:32:06.933 に答える
0

a または b を削除したからといって、ポインターが null に変更されるわけではありません。
参照してください:なぜ delete はポインタを null にリセットしない
のか 、a に格納されているアドレスを delete 演算子に渡すと考えてください。delete はメモリ アドレスを解放しますが、アドレスを保持している変数は変更しません。
良い戦術は

delete a;
a = null;

削除後のオブジェクトの参照は未定義の動作です。

于 2013-01-08T14:39:25.513 に答える