2010-11-21 6 views
1

Ok everyone、noob question。デストラクタは、動的構造を返す関数のコピーを削除します。

私はテンプレートクラスが単独でリンクされたリストを実装しています。私のプログラム内のあるクラスの関数は、これらのリストの1つを返します。

psList<int> psObj::getList() const { 
return List; 
} 

だから何が起こっていることはリストにうまくその仕事をしていませんし、リストのコピーを作成するコピーコンストラクタキックを返すように呼び出しです。ただし、関数は終了し、範囲外になり、デストラクタを呼び出します。突然、返されたリンクリストが削除されます。これは私のデストラクタが行うものなので、リストを削除して削除します。

私は戻り値の型をコピーされたリストの先頭へのポインタにすることができ、すべてがうまくいくことは理解できますが、私はまだダイナミックのコピーを返す関数を作成できません私が欲しいと思っていても、私はしたいです。

もっとコードを求められました。ここで

は明らかにここに深いコピー

template<class psClass> 
psList<psClass>::psList(const psList &original) { 
    head = NULL; 

    if(original.head != NULL) { 
     psNode<psClass>* iterator = original.head; 
     while(iterator != NULL) { 
      pushback(iterator->data); 
      iterator = iterator->next; 
     } 
    } 
} 

を行いコピーコンストラクタ、デストラクタである。ここ

template<class psClass> 
psList<psClass>::~psList() { 
    erase(); 
} 

が消去機能は、デストラクタの呼び出しです。

template<class psClass> 
void psList<psClass>::erase() { 
    psNode<psClass>* iterator = head; 
    psNode<psClass>* buff; 

    while(iterator != NULL) { 
     buff = iterator->next; 
     delete iterator; 
     iterator = buff; 
    } 
} 

私は深いコピーと深い破壊をしています。問題は深さではありません。したがって、問題はそうです。元の関数では、ディープコピーが作成され、返されます。関数は有効範囲外になり、ディープデストラクタはコピーに対して呼び出されます。もうコピーしない。

良く、ここで説明するのは、それがGETLIST関数呼び出しの前に、元のリストのデバッガ

でどのように見えるかです。ここで

head 0x616080 
data 2 
next 0x616060 
data 12 
next 0x0 

一度GETLIST関数内

head 0x616080 
data 2 
next 0x616060 
data 12 
next 0x0 

を "リストを返す" 同じことの一覧です。

コピーコンストラクタの最後に「オリジナル」と「this」のリストがあります。

"この"

head 0x63c900 
data 2 
next 0x63a940 
data 12 
next 0x0 

"オリジナル"

head 0x616080 
data 2 
next 0x616060 
data 12 
next 0x0 

すべてがそうでない偉大に見えます。

これでgetList関数に戻り、最後の括弧に入ることにしました。

psList<int> psObj::getList() const { 
return List; 
} // This bracket 

バックこの機能では、リスト一覧

は、あなたがそれを

head 0x616080 
data 2 
next 0x616060 
data 12 
next 0x0 

そして今、我々は

/* 
* No idea what the in chrg thing is or why the debugger is telling me it was 
* optimized out but I mentioned it here cause maybe it has something to do with my 
* problem 
*/ 
this 0x7ffffffe650 
__in_chrg value optimized out 

// Look familiar? well it should cause it is the head of the list I returned. 
head 0x63c900 
data 2 
next 0x63a940 
data 12 
next 0x0 
ありデストラクタが呼び出され、最終的なブラケットにステップということであることを期待するものです

次にbam!私がコピーして返したリストは、デストラクターによって削除されます。なぜなら、スコープから外れるからです。

この迂回の後、元の質問を繰り返してください。デストラクタが上記のコピーを破壊することなく、ディープコピーを使用する関数によって動的構造が返されるようにするにはどうすればよいですか?

もっと要求

// Simple single link node with default constructor initializing the link to NULL. 
template <class psClass> 
struct psNode { 
    psClass data; 
    psNode<psClass>* next; 

    psNode() { 
     next = NULL; 
    } 
}; 

上のコードとプッシュバック機能

template<class psClass> 
void psList<psClass>::pushback(psClass object) { 
    psNode<psClass>* ptr = new psNode<psClass>; 
    ptr->data = object; 

    if(head == NULL) 
     head = ptr; 
    else { 
      //Have to find the tail now 
     psNode<psClass>* tail; 
     psNode<psClass>* iterator = head; 
     while(iterator != NULL) { 
      tail = iterator; 
      iterator = iterator->next; 
     } 
     tail->next = ptr; 
    } 
} 

と尾のはい、私は維持知っているトラックが容易になるだろう。まだ

template <class psClass> 
class psList { 
public: 
    psList(); 
    ~psList(); 
    psList(const psList &original); 
    psList(psNode<psClass>* _head); 

    void erase(); 
    void pushfront(psClass object); 
    void pushback(psClass object); 
    bool isEmpty() const; 
    psNode<psClass>* front() const; 

private: 
    psNode<psClass>* head; 
}; 

ませんオーバーロード代入演算子:ここ

はpsListクラスの定義です。私はこの障害を乗り越えた後にそれを追加するつもりです。

+0

[3つのルール](http://stackoverflow.com/questions/4172722/)に慣れておく必要があります。また、これが宿題や学習の練習でない限り、自分のリンクリストを実装することは絶対に推奨されません。 – fredoverflow

+0

返されるリンクリストは、returnステートメントでコピーされ、元のものが返された関数のローカルなので、確実に破棄されるはずです。 –

+0

おそらく 'psList'、' psNode'と 'psList :: pushback'がどのように定義されているかを示してください。 –

答えて

0

が効果的である:

psList<int> psObj::getList() const { return psList<int>(List); } 

これはメンバーListgetListが呼び出されたフレームの間でコピーし、それをのコピーを作成します。それがコピーされる方法は、それをどのように呼び出すかによって異なります。あなたは

psList<int> newList = obj.getList(); // same as psList<int> newList(obj.getList()); 

のように、このデータから新しいpsListオブジェクトを、構築した場合はコピーコンストラクタが使用されています。多くの場合、2つのコピーはRVOによって1つのコピーに縮小されます。また

、あなたが代入演算子を経て、

psList<int> newList; 
newList = obj.getList(); 

元のオブジェクトの状態が返された結果からのデータに置き換えているのように、既存のオブジェクトにコピーする場合。自分自身を宣言していない場合、コンパイラはあなたのために一般的なassingment演算子を定義します。しかし、これは単純にオブジェクトの各メンバーのコピーになります。つまり:呼び出し元のコードで非常に

psList & psList::operator=(const psList& src) { 
    head = src.head; 
} 

次のように何が起こることです:

あなたのケースであなたが望むものではなく、何をやるべきことはコピー代入してくださいました
psList<int> newList; // psList default constructor called 
newList = obj.getList(); // 1) obj.List copied via copy constructor within getList 
         // 2) copy of obj.List copy-assigned to newList (simple copy of head pointer) 
         // 3) copy of obj.List destructed 
// newList now has head pointing to destroyed data 

真に目的の深いコピーを作成しました(すでに実装しているコピーコンストラクタを使って行う方法については、copy-and-swapを参照してください)。

したがって、rule of three:デストラクタ、コピーコンストラクタ、およびコピー割り当てのいずれかの独自の実装を定義する必要がある場合は、すべてを定義する必要があります(または、少なくともコピー割り当てを宣言して、あなたのクラスはコピー不可能です)。

さておき、なぜ参照戻らないよう:

const psList<int> & psObj::getList() const { return List; } 

をし、呼び出し元の関数はコピーを作成するかどうかを決定しますか?

psList<int> localList(localPsObj.getList()); 
+0

どのようにこの結論に達しましたか?コンストラクタの未知の部分( 'pushback')は、' psNode'の 'data'部分だけを受け取るので、元の' psNode'へのポインタを再構築するのは難しいでしょう。 –

+0

コピーコンストラクタは、間違いなくディープコピーを作成します。 pushbackは空白の新しいノードへのポインタを作成し、データはこのノードにコピーされ、既に作成されたリストの最後のノードが(nullにリンクされる前に)リンクされます。新しいノードのリンクはすでにnullを指しているため、そこでは何も実行されません。 –

+0

@Charles:良い点は、 'pushback'に渡されたデータだけが欠落していました。私のごみの答えを、より有益なものに置き換えました。 – beldaz

2

psListのコピーコンストラクタは、深いコピーコンストラクタではなく、浅いコピーを作成するように見えます。一般に、クラス内のリソースを管理する場合は、単純なコピーコンストラクタ、代入演算子、およびデストラクタ(「big three」)が必要です。 psListのコードをお知らせください。次のようにあなたが現在何をしている

+0

いいえ、深いコピーと深い破壊両方 –

関連する問題