在这个简单的代码中无法找到我的内存泄漏

时间:2015-02-14 01:13:29

标签: c++ pointers memory-leaks nullptr

我100%肯定我在丢失之前从堆中删除内存方面已经涵盖了所有基础,但valgrind似乎不同意。任何帮助找到以下代码中的泄漏将不胜感激!我似乎无法弄清楚导致它的原因

                    Card * S = new Card[subsetSize];
                    Card * M = nullptr;
                    int subsetPrice = 0, subsetProfit = 0;
                    for(int i = 0; i < subsetSize; i++){
                            S[i] = problemCards[cardIndexesToAdd[i]];
                            subsetPrice += S[i].getPrice();
                            subsetProfit += S[i].getProfit();
                    }

                    // Evaluate the subset's cost and profit
                    if(subsetPrice <= maxToSpend){
                            if(subsetProfit > maxProfit){
                                    maxProfit = subsetProfit;
                                    if(M != nullptr)
                                            delete[] M;
                                    M = S;
                                    S = nullptr;
                                    mSize = subsetSize;
                            }
                    }
                    else{
                            if(S != nullptr){
                                    delete[] S;
                                    S = nullptr;
                            }
                    }
                    // output code for M
                    if(M != nullptr)
                        delete[] M;

4 个答案:

答案 0 :(得分:4)

S (subsetPrice <= maxToSpend) == true(subsetProfit > maxProfit) == false

时,您会泄漏{{1}}

答案 1 :(得分:4)

让我们一步一步看看你在做什么:

  1. 为S.分配内存。将M设置为空。

    Card * S = new Card[subsetSize];
    Card * M = nullptr;
    
  2. 如果满足条件A(subsetPrice&lt; = maxToSpend),并且满足条件B(subsetProfit&gt; maxProfit),则交换M指向为S分配的内存,并将S设置为指向null。 / p>

    if (subsetPrice <= maxToSpend){
        if (subsetProfit > maxProfit){
            maxProfit = subsetProfit;
            if (M != nullptr)
                delete[] M;
            M = S;
            S = nullptr;
            mSize = subsetSize;
        }
    }
    
  3. 如果不满足条件A,则释放内存S指向的内容。

    else{
        if(S != nullptr){
            delete[] S;
            S = nullptr;
        }
    }
    
  4. 释放M指向的内存。

    if(M != nullptr)
        delete[] M;
    
  5. 因此,如果满足条件A,但条件B不满足,那么S既不会被释放也不会转移到M!内存泄漏。

答案 2 :(得分:1)

我建议学习编写代码,以免开始引起此类问题,而不是扮演侦探并追踪这种特殊的内存泄漏。最明显的第一点是使用std::vector 而不是尝试自己处理所有内存管理。可能没有其他单一步骤能够像习惯这样做那么快地消除尽可能多的问题。

当你使用它时,几乎所有的所有问题都不再存在,因为你有一个拥有内存的对象,当该对象超出范围时,它会释放内存它拥有 - 完全自动。它甚至可以在/如果抛出异常时工作,您的代码甚至不会尝试来处理。

std::vector<Card> subset(subsetSize);

for (int i=0; i<subsetSize; i++) {
    subset.push_back(problemCards[cardIndexesToAdd[i]]);
    subsetPrice += subset.back().getPrice();
    subsetProfit += subset.back().getProfit();
}

if (subsetProfit > maxProfit && subsetPrice < maxPrice) { 
    maxSubset = std::move(subset);
    maxProfit = subsetProfit;
}

// code to print out maxSubset goes here

如果您想更进一步,可以使用(例如)Boost indirect_iterator代替cardIndexesToAdd。这样您就可以将标准算法直接应用于您关心的子集。有了这个,您可以很容易地避免复制当前子集 - 您只需使用indirect_iterator来代替原始集合迭代。

您还可以为operator+定义一个Card来汇总价格和利润字段:

Card operator+(Card const &left, Card const &right) { 
    return Card(left.price+right.price, left.profit+right.profit);
}

有了这个,以及前面提到的indirect_iterator,将子集的利润加起来可能是这样的:

Card subset_stats = std::accumulate(subset.begin(), subset.end(), Card());

同样,我们可以为Card定义一个比较运算符,根据利润和/或成本生成结果:

// Assuming we care primarily about maximizing profit, secondarily about
// price, so if one subset produces more profit, it's better. If they produce
// the same profit, the lower cost wins.
bool operator<(Card const &a, Card const &b) { 
    if (a.profit == b.profit)
       return a.price < b.price;
    return b.profit < a.profit;
}

有了这个,我们可以直接比较Card,例如:if (a < b) ..并获得有意义的结果。

答案 3 :(得分:0)

很抱歉,这将是一个评论,但我是新来的,不能这样做。

对于内存不足, new 不需要检查nullptr。 THX @杰里棺

所有delete []都在if()或嵌套if()语句中。如果这个泄漏,你就错过了使用delete []添加else而你缺少else语句。

这似乎是一个片段,但事实上,我认为没有理由让M或它分配S.你应该考虑在最后进行一次删除。