2017-11-01 29 views
-4

ここで別のリストのコピーであるリストを作成しました。このリストはコピーと呼ばれます。私はコピーされた数字のシャッフルリストを作成しようとしています。ユーザーは最初のリストのサイズ(いくつのカードが必要か)を入力し、リストが作成され、ここではそのリストがシャッフルされます。しかし、何らかの理由でユーザーが20を入力すると、このエラーが発生します。std :: listの項目を消去するときのバグ

output(41432,0x7fff7389e000) malloc: *** error for object 0x7fff55638490: 
pointer being freed was not allocated 
*** set a breakpoint in malloc_error_break to debug 
Abort trap: 6 

ここは私のコードのセクションです。 while(!copied.empty())ループを削除すると、最初のリストから新しいリストに位置 "r"に "it"の値が入るので、うまく動作します。しかし、私はそれぞれの "r"のためにそれを行う必要があります。

list<size_t> copied; 
    copied.insert(copied.end(), cards.begin(), cards.end()); 
    int r = rand()%(((copied.size()+1) - 0) + 1) + 0; 

    list<size_t>::const_iterator it = copied.begin(); 

    while(!copied.empty()){ 
     for(int i = 0; i < r; i++) { 
      it++;} 
     shuffle.push_back(*it); 
     copied.erase(it);} 
+2

'it'は、'リスト :: const_iterator'として定義されている間 ' std :: list' 'erase()'メソッドは 'iterator'に対してのみ定義されています。 'iterator'と' const_iterator'は別個の型です。また、繰り返しながらリストから要素を削除する際のこの質問を参照してください:https://stackoverflow.com/questions/596162/can-you-remove-elements-from-a-stdlist-while-iterating-through-it – Polb

+0

(1 + 1-0 + 1)は3なので、rは0と2の間の任意の値であることができるので、 'copied.begin()'は0になります。 0と2の間のどこかで増分することができます。間違って 'copied.begin() 'を1回だけインクリメントして、逆参照しようとしていて、意味のある結果を期待しています。あなたの問題は基本的な数学であり、イテレータと0ベースの配列/コンテナのインデックス作成の仕組みをよりよく把握する必要があります。 –

+1

また、 'erase'はイテレータを無効にします。あなたはそれを増やしたり、リストの残りの部分に戻ることはできません。 – Beta

答えて

3

問題はcopied.erase(it)はイテレータitを無効にすることであるので、任意のその後の使用は未定義の動作です。 eraseが消去されたものの後の次の要素への有効なイテレータを返しますので、あなたは代わりに

it = copied.erase(it); 
if (it == copied.end()) it = copied.begin(); 

を使用することができます。それはおそらくする必要がありますので、あなたはまた、リストの末尾から実行しているforループにit++を心配する必要があります。

for(int i = 0; i < r; i++) { 
    if (++it == copied.end()) 
     it = copied.begin(); } 
+0

いいえ、この回答は間違っています。表示されているコードを慎重に確認してください。これは、表示されたコードの文字化けのため、このようにしか見えません。 'erase();'は外部ループを終了するだけです。すべてのイテレータのインクリメントは 'erase()'の前に行われ、インクリメント自体は問題あり、コンテナの最後から実行されます。これは単なる悪い質問です。 –

+0

@SamVarshavchik:私は投稿されたコードで何ができるのでしょうか?意味的にナンセンスなら構文的に正しいです。 'erase'はループを終了させません - ループは消去後も継続し、再びループします。 –

+0

それはまさに投稿されたコードです。投稿されたコードは、無効化されたイテレータをインクリメントしません。インクリメント自体は 'erase()'の前にイテレータを無効にしました。 'erase();'は***外側***ループを終了します。中カッコを数えます。 –

関連する問題