【问题标题】:Can't find my memory leak in this simple code在这个简单的代码中找不到我的内存泄漏
【发布时间】:2015-02-14 01:13:29
【问题描述】:

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

【问题讨论】:

  • 所以你是 100% 肯定的......而且错了? o.O
  • @LightnessRacesinOrbit 是的,它发生了。感谢您难以置信的不必要的反对。
  • @Mr.Smith:实际上是这样,如果它可以诱使 OP 调整这种行为。那么他或她将来会因为错误的假设而犯更少的错误。看大局。
  • @LightnessRacesinOrbit 添加对 nullptr 的检查只是习惯
  • 投下必要的反对票。

标签: c++ pointers memory-leaks nullptr


【解决方案1】:

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

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

    Card * S = new Card[subsetSize];
    Card * M = nullptr;
    
  2. 如果满足条件A(subsetPrice 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!内存泄漏。

【讨论】:

    【解决方案2】:

    (subsetPrice &lt;= maxToSpend) == true(subsetProfit &gt; maxProfit) == false 时,您会泄漏S

    【讨论】:

    • 将M设置为S指向的地址,然后将S设置为nullptr不是有效操作吗?内存仍然占。
    • 如果(subsetProfit &gt; maxProfit) == false,这个块不会被执行
    • 哇!我不敢相信我错过了
    【解决方案3】:

    与其扮演侦探并追踪这种特殊的内存泄漏,我建议您学习编写代码,以免一开始就引发此类问题。最明显的第一点是使用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 间接迭代器来代替您的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 定义一个比较运算符,根据利润和/或成本产生结果:

    // 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 &lt; b) ..,并得到有意义的结果。

    【讨论】:

      【解决方案4】:

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

      对于内存不足,new 不需要检查 nullptr。谢谢@jerry-coffin

      您所有的 delete [] 都在 if () 或嵌套的 if () 语句中。如果泄漏,您错过了添加带有 delete [] 的 else 并且您缺少 else 语句。

      这似乎是一个 sn-p,但实际上,我看不出 M 或其分配 S 的原因。您可能应该考虑在最后进行一次删除。

      【讨论】:

      • new 在内存不足的情况下不会返回空指针——它会引发异常(除非您使用new(nothrow) 形式)。
      • @Jerry Coffin,是的,你是对的。我的错误。我的大部分代码都进入了默认内存分配行为已被自定义库(即游戏控制台)覆盖的应用程序,其中不能容忍异常。
      猜你喜欢
      • 1970-01-01
      • 2015-01-24
      • 1970-01-01
      • 1970-01-01
      • 2012-01-21
      • 1970-01-01
      • 1970-01-01
      • 2019-08-19
      • 1970-01-01
      相关资源
      最近更新 更多