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

Can't find my memory leak in this simple code

我 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;

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

时你泄漏了 S

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

  1. 为S分配内存。将M指向null。

    Card * S = new Card[subsetSize];
    Card * M = nullptr;
    
  2. 如果满足条件A(subsetPrice <= maxToSpend),并且满足条件B(subsetProfit > maxProfit),交换M指向分配给S的内存,并设置S指向null .

    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;
    

因此,如果满足条件 A,但不满足条件 B,则 S 既不会被释放,也不会转移给 M!内存泄漏。

抱歉,这是一条评论,但我是新来的,还不能这样做。

new 不需要检查 nullptr 是否内存不足。 Thx@jerry-coffin

你所有的 delete [] 都在 if () 或嵌套的 if () 语句中。如果这个泄漏,你错过了添加一个带有删除 [] 的 else 并且你错过了 else 语句。

这似乎是一个片段,但事实上,我认为没有理由使用 M 或其分配给 S。您可能应该考虑在最后进行一次删除。

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

当你使用它的时候,整个class几乎所有的问题都不复存在了,因为你有一个拥有内存的对象,而当那个对象超出范围,它会完全自动释放它拥有的内存。即使抛出 when/if 异常,您的代码甚至 尝试 都不会处理,它也能正常工作。

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 就地迭代原始集合。

您还可以为 Card 定义一个 operator+,它将对价格和利润字段求和:

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 定义一个比较运算符,它根据利润 and/or 成本生成结果:

// 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;
}

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