C ++のSTLプライオリティキュー挿入bad_alloc例外
-
25-09-2019 - |
質問
私は、マッチングのidのためのメモリとルックスから文書IDの長いリストに読み込み、クエリプロセッサに取り組んでいます。それが1つを見つけると、それはDOCID(int型)と、文書のランク(ダブル)を含むDOC構造体を作成し、プライオリティキューへのそれをプッシュします。私の問題は、長いリストを持っているためワード(複数可)を検索するとき、私はキューに上のDOCをプッシュしようとすると、私は次の例外を取得することです: QueryProcessor.exeで0x7c812afbで未処理の例外:マイクロソフトC ++の例外:メモリ位置でのstd :: bad_alloc 0x0012ee88 ..
単語が短いリストを持っている場合は、は、それが正常に動作します。私は、特定の行まで、DOCのキューへの私のコードのいくつかの場所で、それらはすべての作業をプッシュしようとしました。その後、私は上記のエラーを取得します。最も長いリストが読み込まので、私は1 MB未満であると、私は私が割り当てることを、すべてのメモリを解放間違っているものにとして損失で完全にしています。私はそれを保持する能力を持っているキューにDOCをプッシュしようとすると、なぜそこに突然(私はプライオリティキューのための基礎となるデータ構造として予約十分なスペースとベクトルを使用)bad_alloc例外すべきですか?
私はこのような質問は、すべてのコードを見ずに答えることはほとんど不可能であることを知っているが、それはここに投稿するためには長すぎるのです。私は私ができる限り入れていると私は私の知恵末端だから心配そうに、誰かが私に答えを与えることができることを期待しています。
はNextGEQ機能がブロックによってdocidsブロックの圧縮されたブロックのリストを読み込みます。それは(別のリストで)ブロック内lastdocidが渡されたDOCIDよりも大きいことを見ればそれはそれは正しいものを見つけるまで、それがブロックして検索を解凍し、です。各リストには、各圧縮チャンクとチャンクの最後のDOCIDの長さを持つリストに関するメタデータで始まります。メタデータの先頭にdata.iqueryポイント。メタデータに関数が現在どこにdata.metapointerポイント。そして、非圧縮の1 docidsのブロックの先頭にdata.blockpointerポイントがある場合。それがすでに解凍されたことを認識した場合、それだけで検索します。私は機能を初めて呼び出すときに、以下の、それはブロックを解凍し、DOCIDを見つけました。その作品の後にキューにプッシュ。二回目は、それがさえ解凍する必要はありません。それは、新しいメモリが割り当てられていないが、その時間の後、キューへの上にプッシュすることはbad_allocエラーを与えています。
編集:私はいくつかのより多くのそれをコンパイルする必要があること私のコードをクリーンアップ。後者は長いですが、私は問題がそれでヒープ破損のどこかに起因していると思うので、私はまた、OpenList()とNextGEQ機能に追加しました。どうもありがとう!
struct DOC{
long int docid;
long double rank;
public:
DOC()
{
docid = 0;
rank = 0.0;
}
DOC(int num, double ranking)
{
docid = num;
rank = ranking;
}
bool operator>( const DOC & d ) const {
return rank > d.rank;
}
bool operator<( const DOC & d ) const {
return rank < d.rank;
}
};
struct listnode{
int* metapointer;
int* blockpointer;
int docposition;
int frequency;
int numberdocs;
int* iquery;
listnode* nextnode;
};
void QUERYMANAGER::SubmitQuery(char *query){
listnode* startlist;
vector<DOC> docvec;
docvec.reserve(20);
DOC doct;
//create a priority queue to use as a min-heap to store the documents and rankings;
priority_queue<DOC, vector<DOC>,std::greater<DOC>> q(docvec.begin(), docvec.end());
q.push(doct);
//do some processing here; startlist is a pointer to a listnode struct that starts the //linked list
//point the linked list start pointer to the node returned by the OpenList method
startlist = &OpenList(value);
listnode* minpointer;
q.push(doct);
//start by finding the first docid in the shortest list
int i = 0;
q.push(doct);
num = NextGEQ(0, *startlist);
q.push(doct);
while(num != -1)
{
q.push(doct);
//the is where the problem starts - every previous q.push(doct) works; the one after
//NextGEQ(num +1, *startlist) gives the bad_alloc error
num = NextGEQ(num + 1, *startlist);
//this is where the exception is thrown
q.push(doct);
}
}
//takes a word and returns a listnode struct with a pointer to the beginning of the list
//and metadata about the list
listnode QUERYMANAGER::OpenList(char* word)
{
long int numdocs;
//create a new node in the linked list and initialize its variables
listnode n;
n.iquery = cache -> GetiList(word, &numdocs);
n.docposition = 0;
n.frequency = 0;
n.numberdocs = numdocs;
//an int pointer to point to where in the metadata you are
n.metapointer = n.iquery;
n.nextnode = NULL;
//an int pointer to point to the uncompressed block of data, if there is one
n.blockpointer = NULL;
return n;
}
int QUERYMANAGER::NextGEQ(int value, listnode& data)
{
int lengthdocids;
int lengthfreqs;
int lengthpos;
int* temp;
int lastdocid;
lastdocid = *(data.metapointer + 2);
while(true)
{
//if it's not the first chunk in the list, the blockpointer will be pointing to the
//most recently opened block and docpos to the current position in the block
if( data.blockpointer && lastdocid >= value)
{
//if the last docid in the chunk is >= the docid we're looking for,
//go through the chunk to look for a match
//the last docid in the block is in lastdocid; keep going until you hit it
while(*(data.blockpointer + data.docposition) <= lastdocid)
{
//compare each docid with the docid passed in; if it's greater than or equal to it, return a pointer to the docid
if(*(data.blockpointer + data.docposition ) >= value)
{
//return the next greater than or equal docid
return *(data.blockpointer + data.docposition);
}
else
{
++data.docposition;
}
}
//read through the whole block; couldn't find matching docid; increment metapointer to the next block;
//free the block's memory
data.metapointer += 3;
lastdocid = *(data.metapointer + 3);
free(data.blockpointer);
data.blockpointer = NULL;
}
//reached the end of a block; check the metadata to find where the next block begins and ends and whether
//the last docid in the block is smaller or larger than the value being searched for
//first make sure that you haven't reached the end of the list
//if the last docid in the chunk is still smaller than the value passed in, move the metadata pointer
//to the beginning of the next chunk's metadata; read in the new metadata
while(true)
// while(*(metapointers[index]) != 0 )
{
if(lastdocid < value && *(data.metapointer) !=0)
{
data.metapointer += 3;
lastdocid = *(data.metapointer + 2);
}
else if(*(data.metapointer) == 0)
{
return -1;
}
else
//we must have hit a chunk whose lastdocid is >= value; read it in
{
//read in the metadata
//the length of the chunk of docid's is cumulative, so subtract the end of the last chunk
//from the end of this chunk to get the length
//find the end of the metadata
temp = data.metapointer;
while(*temp != 0)
{
temp += 3;
}
temp += 2;
//temp is now pointing to the beginning of the list of compressed data; use the location of metapointer
//to calculate where to start reading and how much to read
//if it's the first chunk in the list,the corresponding metapointer is pointing to the beginning of the query
//so the number of bytes of docid's is just the first integer in the metadata
if( data.metapointer == data.iquery)
{
lengthdocids = *data.metapointer;
}
else
{
//start reading from the offset of the end of the last chunk (saved in metapointers[index] - 3)
//plus 1 = the beginning of this chunk
lengthdocids = *(data.metapointer) - (*(data.metapointer - 3));
temp += (*(data.metapointer - 3)) / sizeof(int);
}
//allocate memory for an array of integers - the block of docid's uncompressed
int* docblock = (int*)malloc(lengthdocids * 5 );
//decompress docid's into the block of memory allocated
s9decompress((int*)temp, lengthdocids /4, (int*) docblock, true);
//set the blockpointer to point to the beginning of the block
//and docpositions[index] to 0
data.blockpointer = docblock;
data.docposition = 0;
break;
}
}
}
}
ありがとうございました、BSGます。
解決
は、ヒープ破損があり、メモリを排気することになっていないと仮定すると、ヒープが破損して取得することができ、最も一般的な方法は、削除(または解放)を2回同じポインタをすることです。これは単純に削除するために、すべてのあなたの呼び出しをコメントアウト(または無料)することにより、問題がある場合は、非常に簡単に見つけることができます。これはあなたのプログラムがふるいのように漏れることになりますが、それは実際にあなたはおそらく、問題を特定したクラッシュしていない場合ます。
破損ヒープの他の一般的な原因の原因は、これまで、ヒープ上に割り当てられていないポインタを削除(または解放)されます。汚職の2つの原因を区別することは必ずしも容易ではありませんが、あなたの最初の優先順位は腐敗が実際に問題があるかどうかを確認する必要があります。
(注)削除されている事がブレークプログラムのセマンティクスと呼ばれていない場合はデストラクタを持っている場合は、このアプローチはあまりうまく機能しません。
他のヒント
QUERYMANAGER::OpenList
値によってlistnodeを返します。 startlist = &OpenList(value);
では、その後、返された一時オブジェクトのアドレスを取るに進みます。一時的に離れて行くとき、あなたは時間のためにデータにアクセスできる可能性があり、その後、それが上書きされます。あなただけのスタック上の非ポインタlistnodeのstartlistを宣言し、直接それを戻り値を代入できますか?その後、他の用途の前に*を削除し、その修正場合、問題を参照してください。
あなたが試すことができますもう一つは、これは本当にあるとタスクを自動化し、どのくらいあなたがいる快適どのくらいのコードに応じて、boost::shared_ptr<>
ような何か具体的には、スマートポインタですべてのポインタを交換しています。スマートポインタは、すべての答えはありませんが、生のポインタよりも少なくともより安全です。
すべてのご協力いただきありがとうございます。あなたは、ニール正しかった - 私は壊れている私のヒープに管理している必要があります。私はまだ確かにそれを引き起こしていたものではないんだけど、私はmalloc関数へのmalloc(numdocidsは5 *)(256)を変更したときに、それは魔法のクラッシュ停止しました。私は私のmallocを、実際に成功したかどうかをチェックしている必要がありますと仮定します!再度、感謝します! BSG