【问题标题】:std::map values lost after returning返回后 std::map 值丢失
【发布时间】:2013-04-14 23:26:37
【问题描述】:

如何在将映射从一个函数传递到另一个函数时正确处理内存。

我有一个函数可以返回它构建的地图。值对象是一个类 foo。 我在三个不同的位置打印 foo ,它们都给出不同的值。第一次,它给出了正确的值。第二个和第三个是垃圾。

我知道我必须在正确的位置创建 Foo 对象指针。

我想知道在哪里?

std::map<int,Foo*> function_that_returns_the_map(){

  std::map<int,Foo*> myMap; 

  {

    int v = 0; 
    Foo *b = new Foo();

    // PRINTING FOO FIRST

    std::cout<<""<<*b<<endl;

    myMap.insert(std::pair<int,Foo*>(v,b))

  }

  // PRINTING FOO AGAIN 

  for(map<int,Foo*>::iterator it = myMap.begin();
  it != myMap.end(); ++it)
  {      
    std::cout << " " << *(it->second) << "\n";
  }


  return myMap;
  }

std::map<int, Foo*> myMap;
myMap = function_that_returns_the_map();

//PRINTING FOO AGAIN.

 std::map<int, Board*>::iterator it = myMap.begin();
 for (it=myMap.begin(); it!=myMap.end(); ++it)
   cout<<" "<<*(it->second)<<endl;  

Click here 查看我的实际代码。

更新:Foo 的成员变量未使用“new”运算符分配。因此,一旦超出范围,它们就会超出范围并具有垃圾值。

【问题讨论】:

  • 请发布无需修改即可演示问题的代码。您是否意识到您实际上并没有将b 放入地图中?
  • 也许你想要myMap.insert(std::make_pair(v, b))。不要忘记释放内存。
  • “打印 foo”是什么意思?您不能打印课程。请显示实际打印的代码而不是 cmets。
  • @JBentley 我重载了
  • 我已经编辑了我的评论,以请求代码。就像我说的,你不能打印一个类,所以说“我打印 foo”没有任何意义。

标签: c++ map


【解决方案1】:

您的代码中有很多小错误(我认为这只是拼写错误)。我已经修复了这些并提供了一个 Foo 类,它编译并运行良好,在所有三个地方都打印了正确的值:

#include <iostream>
#include <map>

struct Foo
{
   Foo() : someValue(5) {};
   int someValue;
};

std::map<int,Foo*> function_that_returns_the_map()
{
   std::map<int,Foo*> myMap;
   {
      int v = 0; 
      Foo *b = new Foo();
      std::cout << (*b).someValue << std::endl; // PRINTING FOO FIRST
      myMap.insert(std::pair<int,Foo*>(v,b));
   }

   // PRINTING FOO AGAIN
   std::map<int, Foo*>::iterator it = myMap.begin();
   for(it; it != myMap.end(); ++it)
   { 
      std::cout << it->second->someValue << "\n";
   }
   return myMap;
}

int main()
{
   std::map<int, Foo*> myMap;
   myMap = function_that_returns_the_map();

   //PRINTING FOO AGAIN.

   std::map<int, Foo*>::iterator it = myMap.begin();
   for (it; it!=myMap.end(); ++it)
   std::cout << it->second->someValue << std::endl;
   return 0;
}

Click here 查看输出。

因此,问题必须出在您的问题中未提及的内容中。为了能够进一步提供帮助,我们需要查看真实代码。

【讨论】:

  • JBentley,谢谢。您的代码表明指针没有任何问题。我试图找出问题所在。一旦我这样做,我会将您的答案标记为正确。同时,我把所有涉及的功能都放在了here。如果你能调查一下,我将不胜感激。
  • 发现错误,我在填写 Foo 的值时没有使用 new 运算符。您在 Orion 回答的解释评论中您说“Foo 对象本身仍在堆中的内存中,因为您使用 new 创建了它”让我意识到我没有使用 new 来创建存储在 Foo 中的数组。谢谢!
【解决方案2】:

确保您确实使用正确的值创建了 std::pair

myMap.insert(std::pair<int,Foo*>(v, b));
//                               ^^^^

或者使用std::make_pair:

myMap.insert(std::make_pair(v, b));

【讨论】:

  • 道歉。我在代码中犯了一个错误。事实上,我正在使用 v 和 b 值。我在重写代码时错过了它们。
  • 我的问题是:我应该在哪里创建 foo,以便它的值在调用函数的映射中可用,尽管映射存储指针?
【解决方案3】:

您在哪里评论过“在此处打印 FOO”,您是如何编译它的?您不能通过 b 局部变量在其中任何一个地方打印 Foo,因为它超出了范围。相反,您必须从地图中检索对象

我对您的代码进行了以下更改,一切正常:

class Foo
{
public:
    const int Value;
    Foo(int value) : Value(value) // add some kind of identifier to Foo so we can check it's not garbage
    { }
};

std::map<int,Foo*> function_that_returns_the_map()
{
    std::map<int,Foo*> myMap; 

    { // introducing a new scope

        int v = 0; 
        Foo *b = new Foo(98765);

        // PRINTING FOO HERE.
        std::cout << b->Value << std::endl;

        myMap.insert(std::pair<int,Foo*>(v,b));
    } // v, b go out of scope, are no longer accessible

    // PRINTING FOO HERE.
    std::cout << myMap[0]->Value << std::endl; // we can't use v, b anymore, so go fish in the map to find the Foo

    return myMap;
}

void main()
{
    std::map<int, Foo*> myMap;
    myMap = function_that_returns_the_map();

    //PRINTING FOO HERE.
    std::cout << myMap[0]->Value << std::endl; // we can't use v, b anymore, so go fish in the map to find the Foo
}

关键是范围。 C++ 中的花括号表示范围。在该范围内声明的任何局部变量都不能在其外部使用。希望这将有助于解释它。如果没有,请评论任何没有意义的地方。

PS:记住,因为你已经使用new 来创建你的Foo 对象,你必须在某个地方使用delete 来清理它们,否则你的程序会内存泄漏。因此,人们通常不会将指针直接放入映射或列表中。相反,只需将 Foo 对象的副本放入(无指针),或者使用 shared_ptr 等包装器为您管理删除。

【讨论】:

  • 我不确定这个答案是否适用,因为他用更多代码编辑了这个问题。
  • 感谢您的回答。我刚刚修改了代码以显示我的打印方式。我正在从地图中检索值。花括号用于显示范围。映射指向的值是一个指针。由于该分配超出了函数内部花括号的范围,这是否意味着值 98765 不再存在?
  • @srrvnn 您添加的花括号不显示范围,它们创建了一个新范围。
  • @JBentley 我在代码中添加了它们以表明,那段代码在一个新的范围内。我想知道通过这种范围安排,制作对象的最佳位置是什么,这样它们就不会像看起来那样失去价值?
  • @srrvnn 不,只有b 超出范围。 b 是一个指针,其中包含指向 Foo 对象的地址。 Foo 对象本身仍在堆中的内存中,因为您使用 new 创建了它,并且在您使用 delete 之前,任何范围的退出都不会改变这一事实。 myMap 包含b副本(同样包含Foo 对象的地址,而不是Foo 对象本身),因为您插入了它在那里。只要将其插入地图,b 的范围就变得无关紧要。
猜你喜欢
  • 1970-01-01
  • 2011-07-15
  • 1970-01-01
  • 2015-01-15
  • 2021-11-15
  • 1970-01-01
  • 2013-12-31
  • 2023-03-26
  • 1970-01-01
相关资源
最近更新 更多