【问题标题】:C++ memory leak, where?C++ 内存泄漏,在哪里?
【发布时间】:2017-02-09 10:50:03
【问题描述】:

我对下面附加的代码有疑问。本质上它会产生巨大的内存泄漏,但我看不出它发生在哪里。

代码所做的是接收一个称为 prints 的字符串数组,其中包含由 ',' 分隔的数字(节点)(按 desc 节点数排序),查找其他兼容的 prints(兼容意味着其他字符串没有重叠节点 0 被排除,因为每个打印都包含它)并且当所有节点都被覆盖时,它会根据加权图计算风险函数。最后,它保留了风险最低的解决方案。

问题是您在图片中看到的泄漏。我真的不知道它是从哪里来的。

代码如下:

#include "Analyzer.h"

#define INFINITY 999999999

// functions prototypes
bool areFullyCompatible(int *, int, string);
bool contains(int *, int, int);
bool selectionComplete(int , int);
void extractNodes(string , int *, int &, int);
void addNodes(int *, int &, string);

Analyzer::Analyzer(Graph *graph, string *prints, int printsLen) {
    this->graph = graph;
    this->prints = prints;
    this->printsLen = printsLen;
    this->actualResult = new string[graph->nodesNum];
    this->bestResult = new string[graph->nodesNum];
    this->bestReSize = INFINITY;
    this->bestRisk = INFINITY;
    this-> actualSize = -1;
}

void Analyzer::getBestResult(int &size) {

    for (int i = 0; i < bestReSize; i++)
        cout << bestResult[i] << endl;
}

void Analyzer::analyze() {

    // the number of selected paths is at most equal to the number of nodes
    int maxSize = this->graph->nodesNum;
    float totRisk;
    int *actualNodes = new int[maxSize];
    int nodesNum;
    bool newCycle = true;

    for (int i = 0; i < printsLen - 1; i++) {
        for (int j = i + 1; j < printsLen; j++) {

            // initializing the current selection
            if (newCycle) {
                newCycle = false;
                nodesNum = 0;

                extractNodes(prints[i], actualNodes, nodesNum, maxSize);
                this->actualResult[0] = prints[i];
                this->actualSize = 1;
            }

            // adding just fully compatible prints
            if (areFullyCompatible(actualNodes, nodesNum, prints[j])) {
                this->actualResult[actualSize] = prints[j];
                actualSize++;

                addNodes(actualNodes, nodesNum, prints[j]);
            }

            if (selectionComplete(nodesNum, maxSize)) {

                // it means it's no more a possible best solution with the minimum number of paths
                if (actualSize > bestReSize) {
                    break;
                }

                // calculating the risk associated to the current selection of prints
                totRisk = calculateRisk();

                // saving the best result
                if (actualSize <= bestReSize && totRisk < bestRisk) {
                    bestReSize = actualSize;
                    bestRisk = totRisk;
                    for(int k=0;k<actualSize; k++)
                        bestResult[k] = actualResult[k];
                }
            }
        }

        newCycle = true;
    }
}

float Analyzer::calculateRisk() {

    float totRisk = 0;
    int maxSize = graph->nodesNum;
    int *nodes = new int[maxSize];
    int nodesNum = 0;


    for (int i = 0; i < actualSize; i++) {
        extractNodes(this->actualResult[i], nodes, nodesNum, maxSize);

        // now nodes containt all the nodes from the print but 0, so I add it (it's already counted but misses)
        nodes[nodesNum-1] = 0;

        // at this point I use the graph to calculate the risk
        for (int i = 0; i < nodesNum - 1; i++) {
            float add = this->graph->nodes[nodes[i]].edges[nodes[i+1]]->risk;
            totRisk += this->graph->nodes[nodes[i]].edges[nodes[i+1]]->risk;
            //cout << "connecting " << nodes[i] << " to " << nodes[i + 1] << " with risk " << add << endl;
        }
    }

    delete nodes;
    return totRisk;
}

// -------------- HELP FUNCTIONS--------------

bool areFullyCompatible(int *nodes, int nodesNum, string print) {

    char *node;
    char *dup;
    int tmp;
    bool flag = false;

    dup = strdup(print.c_str());
    node = strtok(dup, ",");


    while (node != NULL && !flag)
    {
        tmp = atoi(node);

        if (contains(nodes, nodesNum, tmp))
            flag = true;

        node = strtok(NULL, ",");
    }

    // flag signals whether an element in the print is already contained. If it is, there's no full compatibility

    if (flag)
        return false;

    delete dup;
    delete node;

    return true;
}

// adds the new nodes to the list
void addNodes(int *nodes, int &nodesNum, string print) {

    char *node;
    char *dup;
    int tmp;

    // in this case I must add the new nodes to the list
    dup = strdup(print.c_str());
    node = strtok(dup, ",");

    while (node != NULL)
    {
        tmp = atoi(node);

        if (tmp != 0) {
            nodes[nodesNum] = tmp;
            nodesNum++;
        }

        node = strtok(NULL, ",");
    }

    delete dup;
    delete node;
}

// verifies whether a node is already contained in the nodes list
bool contains(int *nodes, int nodesNum, int node) {
    for (int i = 0; i < nodesNum; i++)
        if (nodes[i] == node)
            return true;
    return false;
}

// verifies if there are no more nodes to be added to the list (0 excluded)
bool selectionComplete(int nodesNum, int maxSize) {
    return nodesNum == (maxSize-1);
}

// extracts nodes from a print add adds them to the nodes list
void extractNodes(string print, int *nodes, int &nodesNum, int maxSize) {

    char *node;
    char *dup;
    int idx = 0;
    int tmp;

    dup = strdup(print.c_str());
    node = strtok(dup, ",");


    while (node != NULL)
    {
        tmp = atoi(node);

        // not adding 0 because every prints contains it
        if (tmp != 0) {
            nodes[idx] = tmp;
            idx++;
        }
        node = strtok(NULL, ",");
    }

    delete dup;
    delete node;

    nodesNum = idx;
}

【问题讨论】:

  • 你应该使用工具来查找泄漏(valgrind、purify、....)

标签: c++ memory-leaks


【解决方案1】:

你忘记删除一些东西,并且对你记得的数组使用了错误的删除形式,例如

float Analyzer::calculateRisk() {

    float totRisk = 0;
    int maxSize = graph->nodesNum;
    int *nodes = new int[maxSize];
    //...
    delete [] nodes; //<------- DO THIS not delete nodes

最简单的解决方案是避免使用原始指针,而是使用智能指针。或者std::vector,如果您只想将内容存储在某个地方以供索引。

【讨论】:

    【解决方案2】:

    您有new 没有对应的delete

    this->actualResult = new string[graph->nodesNum];
    this->bestResult = new string[graph->nodesNum];
    

    这些应该在某处使用delete [] ...删除

    【讨论】:

      【解决方案3】:

      你在analyze()中分配了actualNodes,但你没有在任何地方释放内存:

      int *actualNodes = new int[maxSize];
      

      此外,Analyzer::bestResultAnalyzer::actualResultAnalyzer 的构造函数中分配,但不会在任何地方释放。

      this->actualResult = new string[graph->nodesNum];
      this->bestResult = new string[graph->nodesNum];
      

      如果你必须使用指针,我真的建议使用智能指针,例如std::unique_ptr 和/或 std::shared_ptr 使用 C++11 或更高版本,或 Boost equivalent 使用 C++03 或更早版本。否则,使用容器,例如首选std::vector

      PS:你的代码在分配和释放方面也有很多不匹配。如果内存是使用alloc/calloc/strdup...分配的,它必须使用free释放。如果使用operator new 分配内存,则必须使用operator delete 分配内存。如果使用operator new[] 分配内存,则必须使用operator delete[] 分配内存。而且我猜你当然不应该deletestrtok的返回值。

      【讨论】:

      • 在这种情况下,使用 std::vector&lt;string&gt; 而不是智能指针,OP 会更好。
      猜你喜欢
      • 1970-01-01
      • 2014-10-25
      • 2011-02-05
      • 1970-01-01
      • 2022-06-16
      • 2010-11-17
      相关资源
      最近更新 更多