2011-07-04 3 views
0
#include <iostream> 

using namespace std; 

class Object{}; 

class Connection 
{ 
    public: 
    Connection(Object * _obj); 
    Object * obj; 
    void status(); 
}; 

Connection::Connection(Object * _obj) 
{ 
    obj = _obj; 
} 

void Connection::status() 
{ 
    cout << obj << endl; 
} 


int main() { 
    Object * myObj = new Object(); 

    Connection * myConn = new Connection(myObj); 

    delete myObj; 
    myObj = NULL; 

    cout << myObj << endl; 
    myConn->status(); 
    /* 
    Output is: 

    0 
    0x25ec010 

    but should be: 

    0 
    0 

    */ 
} 

私はこの例ではポインタで作業していると思っていました。だから、同じアドレスを指す2つのポインタがあるので、 "myConn"のポインタもNULLに設定されていない理由を理解できません。オブジェクトへの2番目のポインタがNULLでなくオブジェクトポインタに設定されているのはなぜですか?

答えて

1

ポインタ値をコピーしているため、0であってはなりません。代わりに参考文献(&)を使用してみてください。

多分これは、最良の例ではなく、boost::shared_ptrは、よりよい解決策であるが、このコードは動作します。

// skipped... 
class Connection 
{ 
public: 
    Connection(Object **_obj); 
    Object **obj; 
    void status(); 
}; 

Connection::Connection(Object **_obj) : obj(_obj) { } 
void Connection::status() { cout << *obj << endl; } 

int main() 
{ 
    Object * myObj = new Object(); 
    Connection * myConn = new Connection(&myObj); 
// skipped 
+0

これはどうやってやるの? – ben

+0

これは最良の例ではないかもしれませんが、boost :: shared_ptrはより良い解決策ですが、このコードは動作します: //スキップしました クラスConnection { public: Connection(Object ** _ obj); オブジェクト** obj; void status(); }; Connection :: Connection(Object ** _ obj):obj(_obj) { } void Connection :: status() { cout << * obj << endl; } int main(){ オブジェクト* myObj = new Object(); 接続* myConn =新しい接続(&myObj); //スキップしました – dmirkitanov

+0

@Dmitry M答えを編集するために、このようなコードと改善点を置く方がよいでしょう。そうすれば、より完全になり、適切にフォーマットされます。私はあなたのためにそれを追加しましたが、それがもっとはっきりとできると思ったら編集してください。 – James

1

*myConnあなたmyObjポインタ(あなたがobj = _obj;を言った)のコピーを作りました。コピーはnullに設定されませんでした。 (しかし、それでもまだ無効になっているアドレスを指しているので、逆参照しないでください)

+0

代わりにどうすればよいですか? – ben

+0

適切なディープコピーと、必要なコンストラクタおよび代入演算子についてはどうですか?あなたが何を達成しようとしているのかは分かりませんが、ヒープ割り当てされたメモリを自由に手渡しているので、あなたの現在のデザインはうまくいかないと確信しています。 –

+0

myConnは、イニシャライザによって提供されたオブジェクトがすでに削除されているかどうかを知る必要があります。したがって、yesの場合、myConnは別の方法で動作する必要があります。 – ben

0

Connection :: objはmyObjを指していません。myObjが保持していた値を指しています。だから、もしそれを修正したいのであれば、関数内で値を手動でnullに設定する必要があります。または、objへのポインタを保持する2番目のポインタを作成し、それがnullであるかどうかチェックしますが、それを複雑にするでしょう。

0

ポインタは、それが指すオブジェクトとは別個のエンティティです。

同じオブジェクトを指しているいくつかのポインタは、(同じオブジェクトを指しているという事実を除いて)互いに関係がないため、別々に管理する必要があります。

myObjポインターを使用してオブジェクトを削除した後、有効なオブジェクトを指していないことを示すために、ポインターを正しくNULLに設定すると、投稿したコード例に問題が発生します。しかし、myConn->objポインタは、まだ削除されたオブジェクトを指しています(つまり、ポインタはもはや有効ではありません)。

共有ポインタ(boost::shared_ptr)を使用すると、このような状況に役立ちます。

+0

私は、削除後にNULLへの設定ポインタに同意しません(ただしC言語では便利です)。論理的に見えるかもしれませんが、この習慣は通常他の潜在的な問題を隠します。ポインタが解放された後は、ポインタを有効範囲外にすることでポインタを無用にする必要があります(NULLに設定しないでください)。 –

+0

@Martin:NULLポインタの逆参照(例:コードの間違いのため)は、以前に指したポインタの逆参照よりも目に見える効果(セグメンテーションフォールトなど)を持つため、早期に問題を捕捉すると便利です。妥当な記憶(あなたはさらにそれが起こったことに気付かないかもしれません)。 –

+0

NULLポインタの逆参照はUBです。これはセグメンテーション違反を意味するものではありません。私は、動的メモリマネージャのデバッグ実装が通常はダブル削除(メンバーをNULLに設定することによって隠している)のようなものをキャッチするため、NULLに設定しないことで、より多くの問題を実際にキャッチすることが分かります。 –

関連する問題