繁体   English   中英

性能崩溃 C++(标准向量 bad_allocation)

[英]Performance collapse C++ (std vector bad_allocation)

以下代码是关于实时搜索邻居的。 一旦一个新节点被添加到我的图中,这个节点的函数updateSeqNeighbours就会被调用。 我所知道的是,新节点绝对是添加的最后一个节点的邻居。 在下一步中,我使用这个事实来查看先前添加的节点的邻域,找到最接近新节点的一个,然后在这个邻域中搜索最近的邻域。

我仅重复此示例 3 次,以将一个节点的邻居数量限制为 4,以保持计算的恒定时间范围。 它工作得很好,除了在 ~30 个节点之后计算时间增加得非常快,每个额外的节点导致bad_alloc异常。

#ifndef GRAPH_NODE_H_
#define GRAPH_NODE_H_

#include <vector>
#include <cmath>

#include <iostream>

using namespace std;

class Node {
public:
    double x;
    double y;

    Node* nodePrev;

    vector<Node> seqNeighbours;

    //Constructor
    Node();
    Node(double x, double y);
    virtual ~Node();

    //Operator functions
    Node& operator=(const Node& n);

    //Get&Set
    int getID();

    //Public member functions
    void addNeighbour(Node& n);

    bool isSeqNeighbour(int ID);

    int updateSeqNeighbours();

    double distanceTo(Node& n);

private:
    static int count;
    int ID;

    void _setDefaults();
};

int Node::count = 0;

Node::Node() {
    _setDefaults();
}

Node::Node(double x, double y) {
    _setDefaults();
    this->x = x;
    this->y = y;
}

Node::~Node() {
    // TODO Auto-generated destructor stub
}

//Operator functions
Node& Node::operator=(const Node& n) {
    if (this != &n) {
        ID = n.ID;
            x = n.x;
            y = n.y;
        seqNeighbours.clear();
        seqNeighbours = n.seqNeighbours;
        nodePrev = n.nodePrev;
    }
    return *this;
}

//Get&Set
int Node::getID() {
    return this->ID;
}

//Public member functions
void Node::addNeighbour(Node& n) {
    seqNeighbours.push_back(n);
}

double Node::distanceTo(Node& n) {
    return sqrt((n.x-x)*(n.x-x) + (n.y-y)*(n.y-y));
}

bool Node::isSeqNeighbour(int ID) {
    for (int i = 0; i < seqNeighbours.size(); i++) {
        if (seqNeighbours[i].getID() == ID) {
            return true;
        }
    }
    return false;
}

int Node::updateSeqNeighbours() {
    if (nodePrev == NULL) {
        return 1;
    } else {
        Node seed = *nodePrev;  //previous node as seed
        seqNeighbours.push_back(seed);

            for (int i = 0; i < 3; i++) {
                    if (seed.nodePrev == NULL) break;
                    double minDist = 15353453;
                    Node closest;
                    for (int j = 0; j < seed.seqNeighbours.size(); j++) {
                            double dist = distanceTo(seed.seqNeighbours[j]);
                            if (dist < minDist) {
                                    minDist = dist;
                                    closest = seed.seqNeighbours[j];
                            }
                    }
                    if (minDist < 150) {
                            seqNeighbours.push_back(closest);
                    }
                    seed = closest;
            }
            cout << "neighbours = " << seqNeighbours.size() << endl;
    }
    return 0;
}

void Node::_setDefaults() {
    x = 0;
    y = 0;
    ID = count;
    nodePrev = NULL;
    seqNeighbours.clear();
    count++;
}
#endif /* GRAPH_NODE_H_ */

图形:

#ifndef GRAPH_GRAPH_H_
#define GRAPH_GRAPH_H_

#include <vector>
#include <iostream>
#include "Node.h"

using namespace std;

class Graph {
public:
    Graph();
    virtual ~Graph();

    vector<Node> list;

    void addNode(Node& n);
    void addSeqNode(Node& n);


private:
    void _setDefaults();
};

Graph::Graph() {
    // TODO Auto-generated constructor stub

}

Graph::~Graph() {
    // TODO Auto-generated destructor stub
}

void Graph::addNode(Node& n) {
    list.push_back(n);
}

void Graph::addSeqNode(Node& n) {
    if (!list.empty()) {
        n.nodePrev = &list.back();
    }
    n.updateSeqNeighbours();
    list.push_back(n);
}

void Graph::_setDefaults() {
    list.clear();
}


#endif /* GRAPH_GRAPH_H_ */

我怀疑内存不足会导致这种情况。 然而,每 4 个邻居有 40 个节点对我来说听起来没什么问题。 任何人都知道出了什么问题?

编辑:德语错误,所以我需要猜测:在类 std::bad_alloc 的项目 prSimulation1.exe 中发生异常。 异常地址:'0x5476016'。 进程已停止。

您的seqNeighboursvector<Node> 这意味着它存储邻居本身,而不是指向它们或其索引的指针。 因此,复制构造函数复制所有邻居。 反过来,复制每个邻居需要复制它的邻居,这需要复制他们的邻居,依此类推。 您的作业还复制所有邻居,这需要复制他们的邻居,依此类推。 这意味着每个副本都会成倍增加内存负载,直到系统无法存储所有邻居、邻居的邻居等。

PS:附带说明,称为“列表”的向量是个坏主意。 它就像一个叫做“vector”的列表,一个叫做“map”的集合,或者一只叫做 Dog 的猫。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM