簡體   English   中英

調試Bad_alloc錯誤C ++

[英]Debugging a bad_alloc error c++

當我運行我的代碼時,一切似乎都工作正常,但是經過一定數量的時間步長(通常是〜100,但每次都不同),我得到了錯誤消息:

“在拋出'std :: bad_alloc'實例后調用終止”

不太確定如何進行調試,因為它不會在每次代碼運行時都在同一時間發生。 我將發布我的代碼,但是它很長,而且肯定有點混亂(這是我第一次真正的嘗試用c ++編寫程序的嘗試),但是我將嘗試解釋其結構以及在哪里可以找到錯誤的來源。

基本結構是我有一個“鳥”(我定義的類)數組,它們通過一些非常復雜的計算選擇如何在每個時間步更新自己。 為此,它定期調用函數getVisualState來更新一個鏈表,該鏈表將每個鳥存儲為“可視狀態”。 我相信這是我在仿真過程中動態分配任何內存的唯一時間,因此我想這很有可能是錯誤的來源。 函數Bird :: resetVisualState()在使用完分配的內存后應該將其清除(但似乎我沒有用完內存,至少在任務管理器中監視它)。

如果有人看到任何東西,他們認為這可能是造成問題的根源,或者如果不是我應該如何實際調試的任何建議!

#include <iostream>
#include <cmath>
#include <gsl/gsl_rng.h>
#include <gsl/gsl_randist.h>
#include <ctime>
#include <vector>
#include <algorithm>
#include <fstream>

#include "birdClasses.h"

using namespace std;

/*
nBirds, nSteps, nF, v, dt, birdRad defined in "birdClasses.h"
*/

//define other parameters.
const int nSensors = 20;
const int nMoves = 3; //no. possible moves at each step.
double dTheta = 15*M_PI/180.0; //angle that birds can change their orientation by in a timestep.
double moves[nMoves] = {-dTheta, 0, dTheta}; //possible moves.
double noise = 0.0;
double initBoxX = 20, initBoxY = 20; //size of initial box particles are placed in.
double sensorFrac[nSensors];
double sensorRef[nSensors];
double sensorRange = 2*M_PI/((double)nSensors);
int counter = 0;

int nps = numStates(nMoves,nF);
int *possibleStates = new int[nps];


//variables to record positions and orientations.
double xPositions[nSteps][nBirds], yPositions[nSteps][nBirds], orientations[nSteps][nBirds];

//array to keep track of which collisions are possible.
int couldCollide[nF][nBirds][nBirds];

//function prototypes
bool checkCollision(int i, int nFut, Bird *birds, double xi, double yi);
unsigned long int getVisualState(Bird *birdList, int nFut, int i, double cX, double cY, double cAng);
void updateTree(double exploreX, double exploreY, double exploreO, Bird *bird, int bn, int nFut);

int main()
{
    sensorRef[0] = sensorRange;
    for(int u=1; u<nSensors; u++) sensorRef[u] = sensorRef[u-1] + sensorRange;

    //set up GSL random number generator.
    const gsl_rng_type * Tr;
    gsl_rng * RNG;
    gsl_rng_env_setup();
    Tr = gsl_rng_default;
    RNG = gsl_rng_alloc (Tr);
    gsl_rng_set(RNG,time(NULL));

    //set up output
    ofstream output("output.txt");

    //initialize birds in a box randomly, all with the same orientation.
    Bird birdList[nBirds];

    for(int i=0; i<nBirds; i++) {
        birdList[i].set_position(gsl_ran_flat(RNG,0,initBoxX),gsl_ran_flat(RNG,0,initBoxY));
    }


    //ACTUAL CODE

    int uniqueVisStates[nMoves];
    double cX, cY, fX, fY, exploreX, exploreY, exploreO;


    //main time step loop
    for(int ts=0; ts<nSteps; ts++) {

        //save current positions
        for(int i=0; i<nBirds; i++) {
            xPositions[ts][i] = birdList[i].get_xPos();
            yPositions[ts][i] = birdList[i].get_yPos();
            orientations[ts][i] = birdList[i].get_orientation();
            birdList[i].updateFuture();
        }

        //update list of possible collisions.
        for(int nFut=0; nFut<nF; nFut++) {
            for(int i=0; i<nBirds; i++) {
                cX = birdList[i].get_xPos(); cY = birdList[i].get_yPos();
                counter = 0;
                for(int j=0; j<nBirds; j++) {
                    if(i==j) {
                        continue;
                    } else {
                        fX = birdList[j].get_futureX(nFut); fY = birdList[j].get_futureY(nFut);
                        if((cX-fX)*(cX-fX)+(cY-fY)*(cY-fY) < ((nFut+1)*v*dt+2*birdRad)*((nFut+1)*v*dt+2*birdRad)) {
                                couldCollide[nFut][i][counter]=j;
                                counter++;
                        }
                    }
                }
                if(counter < nBirds) couldCollide[nFut][i][counter]=-1;
            }
        }

        //loop over birds to choose how they update their orientation.
        for(int bn=0; bn<nBirds; bn++) {
            //loop over possible moves bird can make NOW.

            for(int l=0; l<nMoves; l++) {
                uniqueVisStates[l]=0;
            }

            for(int mn=0; mn<nMoves; mn++) {
                for(int l=0; l<nps; l++) {
                    possibleStates[l]=0;
                }
                counter = 0;
                exploreO = birdList[bn].get_orientation() + moves[mn];
                exploreX = birdList[bn].get_xPos() + cos(exploreO)*v*dt;
                exploreY = birdList[bn].get_yPos() + sin(exploreO)*v*dt;
                updateTree(exploreX,exploreY,exploreO,&birdList[0],bn,0);
                vector<int> visStates (possibleStates,possibleStates+counter);
                vector<int>::iterator it;
                sort (visStates.begin(),visStates.end());
                it = unique(visStates.begin(),visStates.end());
                uniqueVisStates[mn] = distance(visStates.begin(),it);

            }
            int maxInd = 0, maxVal = uniqueVisStates[0];
            for(int h=1; h<nMoves; h++) {
                if(uniqueVisStates[h] > maxVal) {
                    maxInd = h; maxVal = uniqueVisStates[h];
                } else if(uniqueVisStates[h]==maxVal) {
                    if(abs(moves[h])<abs(moves[maxInd])) {
                        maxInd = h;
                    }
                }
            }
            birdList[bn].update_Orientation(moves[maxInd]);
            birdList[bn].update_Pos(birdList[bn].get_xPos()+cos(birdList[bn].get_orientation())*v*dt,birdList[bn].get_yPos()+sin(birdList[bn].get_orientation())*v*dt);
        }

        for(int bn=0; bn<nBirds; bn++) birdList[bn].finishUpdate();
        cout << ts << "\n";
    }

    //OUTPUT DATA INTO A TEXT FILE.
    for(int ts=0; ts<(nSteps-1); ts++) {
        for(int bn=0; bn<nBirds; bn++) {
            output << xPositions[ts][bn] << " " << yPositions[ts][bn] << " " << orientations[ts][bn] << "\n";
        }
    }

    delete[] possibleStates;


    return 0;
}

bool checkCollision(int i, int nFut, Bird *birds, double xi, double yi) {
    int cond = 1; int index, counti=0;
    while(cond) {
        index = couldCollide[nFut][i][counti];
        if(index==-1) break;
        double xj = birds[index].get_futureX(nFut);
        double yj = birds[index].get_futureY(nFut);
        if((xi-xj)*(xi-xj)+(yi-yj)*(yi-yj) < 4*birdRad*birdRad) {
            return 1;
        }
        counti++;
        if(counti==nBirds) break;
    }
    return 0;
}

unsigned long int getVisualState(Bird *birdList, int nFut, int i, double cX, double cY, double cAng) {
    //finds the visual state of bird i based on its current "exploring position" and the predicted positions of other birds at timestep nFut.
    //visual state is defined by discretizing the bird's field of view into nSensors (relative to current orientation) and creating a vector of
    //0s and 1s depending on whether each sensor is < half covered or not. This is then converted to an integer (as we are actually interested only
    //in the number of unique visual states.
    double relX, relY, relDist, dAng, s, dTheta, ang1, ang2;
    //clear current visual state.
    birdList[i].resetVisualState();

    for(int j=0; j<nBirds; j++) {
        if(i==j) continue;
        relX = birdList[j].get_futureX(nFut)-cX;
        relY = birdList[j].get_futureY(nFut)-cY;
        relDist = sqrt(relX*relX+relY*relY);
        dAng = acos((cos(cAng)*relX+sin(cAng)*relY)/relDist);
        dTheta = atan(birdRad/relDist);
        s = cos(cAng)*relY - sin(cAng)*relX;
        if( s<0 ) dAng = 2*M_PI-dAng;
        ang1 = dAng - dTheta; ang2 = dAng + dTheta;
        if( ang1 < 0 ) {
            birdList[i].addInterval(0,ang2);
            birdList[i].addInterval(2*M_PI+ang1,2*M_PI);
        } else if( ang2 > 2*M_PI ) {
            birdList[i].addInterval(0,fmod(ang2,2*M_PI));
            birdList[i].addInterval(ang1,2*M_PI);
        } else {
            birdList[i].addInterval(ang1,ang2);
        }
    }
    Node *sI = birdList[i].get_visualState();
    birdList[i].cleanUp(sI);
    int ind1, ind2;
    for(int k=0; k<nSensors; k++) sensorFrac[k]=0.0; //initialize.
    while(sI->next->next != 0) {
        ang1 = sI->value; ang2 = sI->next->value;
        ind1 = floor(ang1/sensorRange); ind2 = floor(ang2/sensorRange);
        if(ind2==nSensors) ind2--; //this happens if ang2 = 2pi (which can happen a lot).
        if(ind1==ind2) {
            sensorFrac[ind1] += (ang2-ang1)/sensorRange;
        } else if(ind2-ind1==1) {
            sensorFrac[ind1] += (sensorRef[ind1]-ang1)/sensorRange;
            sensorFrac[ind2] += (ang2-sensorRef[ind1])/sensorRange;
        } else {
            sensorFrac[ind1] += (sensorRef[ind1]-ang1)/sensorRange;
            sensorFrac[ind2] += (ang2-sensorRef[ind2-1])/sensorRange;
            for(int y=ind1+1;y<ind2;y++) sensorFrac[y] = 1.0;
        }
        sI=sI->next->next;
    }
    //do final interval separately.
    ang1 = sI->value; ang2 = sI->next->value;
    ind1 = floor(ang1/sensorRange); ind2 = floor(ang2/sensorRange);
    if(ind2==nSensors) ind2--; //this happens if ang2 = 2pi (which can happen a lot).
    if(ind1==ind2) {
        sensorFrac[ind1] += (ang2-ang1)/sensorRange;
    } else if(ind2-ind1==1) {
        sensorFrac[ind1] += (sensorRef[ind1]-ang1)/sensorRange;
        sensorFrac[ind2] += (ang2-sensorRef[ind1])/sensorRange;
    } else {
        sensorFrac[ind1] += (sensorRef[ind1]-ang1)/sensorRange;
        sensorFrac[ind2] += (ang2-sensorRef[ind2-1])/sensorRange;
        for(int y=ind1+1;y<ind2;y++) sensorFrac[y] = 1.0;
    }
    int output = 0, multiplier = 1;
    for(int y=0; y<nSensors; y++) {
        if(sensorFrac[y]>0.5) output += multiplier;
        multiplier *= 2;
    }

    return output;
}

void updateTree(double exploreX, double exploreY, double exploreO, Bird *bird, int bn, int nFut) {
    double o,x,y;
    if(checkCollision(bn,nFut,bird,exploreX,exploreY)) return;
    int vs = getVisualState(bird,nFut,bn,exploreX,exploreY,exploreO);
    possibleStates[counter] = vs;
    counter++;
    if(nFut < (nF-1)) {
        for(int m=0; m<nMoves; m++) {
            o = exploreO + moves[m];
            x = exploreX + cos(o)*v*dt;
            y = exploreY + sin(o)*v*dt;
            updateTree(x,y,o,bird,bn,nFut+1);
        }
    } else {
        return;
    }
}

“ birdClasses.h”:

#ifndef BIRDCLASSES_H_INCLUDED
#define BIRDCLASSES_H_INCLUDED

#include <iostream>
#include <cmath>

using namespace std;

//DEFINE SOME GLOBAL PARAMETERS OF THE SIMULATION
const int nBirds = 50;
const int nF = 6; //number of future timesteps to consider.
const int nSteps = 200;
const double v = 20, dt = 0.1, birdRad = 0.2;

int numStates(int numMoves, int nFut) {
    int num = 1; int multiplier = numMoves;
    for(int i=1; i<nFut; i++) {
        num += multiplier;
        multiplier *= numMoves;
    }
    return num;
}

//Node class is just for a linked list (used in constructing the visual states),
class Node {
public:
    int identifier; // 0 is left side of interval, 1 is right side
    double value; //angular value.
    Node *next; //pointer to the next interval.
    void display(Node *start);
};

//printout linked list if necessary (mainly for debugging purposes).
void Node::display(Node *start) {
    if(start != 0) {
        double inter = start->value;
        cout << inter << " ";
        display(start->next);
    }
}

//bird class.
class Bird {
    double currX, currY;
    double updatedX, updatedY;
    double currOrientation;
    double futureX[nF], futureY[nF];
    Node *visualState;
public:
    Bird() {
        currOrientation=0.0; currX = 0.0; currY = 0.0;
        visualState = new Node;
        visualState->value = 0.0;
        visualState->next = new Node;
        visualState->next->value = 0.0;
        visualState->next->next = 0;
    }
    Bird(double x, double y, double o) {
        currX = x; currY = y; currOrientation = o;
        visualState = new Node;
        visualState->value = 0.0;
        visualState->next = new Node;
        visualState->next->value = 0.0;
        visualState->next->next = 0;
    }
    void set_position(double x, double y) {
        currX = x; currY = y;
    }
    double get_xPos() {
        return currX;
    }
    double get_yPos() {
        return currY;
    }
    double get_orientation() {
        return currOrientation;
    }
    double get_futureX(int ts) {
        return futureX[ts];
    }
    double get_futureY(int ts) {
        return futureY[ts];
    }
    //return pointer to first node.
    Node* get_visualState() {
        return visualState;
    }
    void updateFuture() {
        //use current orientation and position to update future positions.
        for(int i=0; i<nF; i++) {
            futureX[i] = currX + v*(i+1)*cos(currOrientation)*dt;
            futureY[i] = currY + v*(i+1)*sin(currOrientation)*dt;
        }
    }
    void update_Pos(double x, double y) {
        updatedX = x;
        updatedY = y;
    }
    //run this after all birds have updated positions:
    void finishUpdate() {
        currX = updatedX;
        currY = updatedY;
    }
    void update_Orientation(double o) {
        currOrientation += o;
    }

    //add the interval defined by [l r] to the visual state.
    void addInterval(double l, double r) {
        int placed = 0; double cL = 0.0; double cR = 0.0;
        if(visualState->value==0.0 && visualState->next->value==0.0) { //then this is first interval to place.
            visualState->value = l;
            visualState->next->value = r;
            placed = 1;
            return;
        }
        Node *curr_L = visualState;
        Node *prev_L = visualState;
        while(placed==0) {
            cL = curr_L->value;
            cR = curr_L->next->value;
            if(l<cL && r<cL) { //add new interval before this one.
                Node *newRoot = new Node;
                newRoot->value = l;
                newRoot->identifier = 0;
                newRoot->next = new Node;
                newRoot->next->value = r;
                newRoot->next->next = curr_L;
                if(curr_L == visualState) {
                    visualState = newRoot;
                } else {
                    prev_L->next->next = newRoot;
                }
                placed = 1;
            } else if(l <= cL && r >= cR) {
                curr_L->value = l;
                curr_L->next->value = r;
                placed = 1;
            } else if(l <= cL && r <= cR) {
                curr_L->value = l;
                placed = 1;
            } else if(l >= cL && r <= cR) {
                placed = 1; //dont need to do anything.
            } else if(l >= cL && l<=cR && r >= cR) {
                curr_L->next->value = r;
                placed = 1;
            }

            if(l > cR && r > cR) {
                if(curr_L->next->next != 0) {
                    prev_L = curr_L;
                    curr_L = curr_L->next->next;
                } else {
                    Node *newEndL = new Node;
                    newEndL->value = l;
                    newEndL->identifier = 0;
                    newEndL->next = new Node;
                    newEndL->next->value = r;
                    newEndL->next->identifier = 1;
                    newEndL->next->next = 0;
                    curr_L->next->next = newEndL;
                    placed = 1;
                }
            }
        }
    }
    //remove any overlaps.
    void cleanUp(Node *start) {
        Node *NP, *NNP; NP = start->next->next;
        if(NP==0) return;
        NNP = start->next->next->next->next;
        double cL = start->value, cR = start->next->value, nL = start->next->next->value, nR = start->next->next->next->value;

        if(nL < cR) {
            if(nR > cR) {
                start->next->value = nR;
            }

            start->next->next = NNP;

        }
        if(NNP!=0) cleanUp(NP);
    }
    //reset the visual state.
    void resetVisualState() {
        Node *cNode = visualState;
        Node *nNode = visualState->next;
        while(nNode != 0) {
            delete cNode;
            cNode = nNode;
            nNode = nNode->next;
        }
        delete cNode;
        delete nNode;
        visualState = new Node;
        visualState->identifier = 0;
        visualState->value = 0.0;
        visualState->next = new Node;
        visualState->next->identifier = 1;
        visualState->next->value = 0.0;
        visualState->next->next = 0;
        return;
    }
};

#endif // BIRDCLASSES_H_INCLUDED

或什至沒有關於我應該如何實際調試的任何建議!

您可以嘗試在gdb中設置捕捉點以捕捉std::bad_alloc異常:

(gdb) catch throw bad_alloc

(請參閱設置捕捉點

如果您能夠在gdb中重現此bad_alloc,則可以查看bt以查看此異常的可能原因。

我認為這是一個邏輯錯誤,不一定與內存有關。

void addInterval(double l,double r)中,您聲明

Node *curr_L = visualState;
Node *prev_L = visualState;

這些指針現在將指向成員visualState指向的對象。

以后,您將visualState更改為指向新創建的節點

Node *newRoot = new Node;
// ....
if(curr_L == visualState) {
  visualState = newRoot;

但您的指針curr_Lprev_L仍將指向visualState之前指向的對象。 唯一更改這些指針的時間是

if(curr_L->next->next != 0) {
  prev_L = curr_L;
  curr_L = curr_L->next->next;

這與

if(WHATEVER_VISUAL_STATE_USED_TO_POINT_TO->next->next != 0) {
  prev_L = curr_L;
  curr_L = curr_L->next->next;

這是你的意圖嗎? 您可以通過在編輯器中查找* curr_L = *來遵循curr_L的分配。

我建議在一個小的數據樣本上測試您的代碼,並確保您的代碼符合您的意圖。 使用調試器或跟蹤輸出。 采用
valgrind,如果您可以使用它,我想您會感謝valgrind的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM