从地图中检索后,地图中的对象已损坏

时间:2015-12-17 18:11:18

标签: c++ c++11

所以我完全编辑了我的问题。 我有map名为mTextMap,其中包含:

typedef std::map<const std::string, Text*>      TextMap;
TextMap mTextMap;

我有以下方法:

void Foo::setUpGame()
{
    Text text(1,2,3,4); //create a Text object
    mTextMap["MainText"] = &text; //save it in the map!
}

Text& Foo::getText(const std::string name)
{
    auto i= mTextMap.find(name);
    return *(i->second); //Gets a reference to the Text that is inside the map
}

现在,如果我这样使用:

Foo foo;
foo.setUpGame();

Text& myText = foo.getText("MainText"); // Why is this corrupted?

对象myText已完全损坏!!

为什么会这样?

3 个答案:

答案 0 :(得分:2)

一般问题似乎是,你认为这一行:

mTextMap["MainText"] = &text;

将文本对象存储在地图中。它没事了!它存储一个指向地图中对象的指针,文本对象本身 - 如你所说 - 在函数结束时自动被破坏。所以现在你的指针指向一个不存在的对象,这会导致观察到的错误。

您的问题有多种解决方案,具体取决于您尝试实现的具体目标以及您将如何处理您的课程。

一种可能性是使用Text对象的地图(而不是指针):

typedef std::map<const std::string, Text>      TextMap;
void Foo::setUpGame()
{
    Text text(1, 2, 3, 4); //create a Text object
    mTextMap["MainText"] = text; //copy it into the map!
}

void Foo::setUpGame()
{       
    mTextMap.emplace("MainText", Text(1, 2, 3, 4)); //Doesn't require Text to be default constructable
}

另一种可能性是在堆上创建文本对象并使用智能指针(例如unique_ptr)

typedef std::map<const std::string, std::unique_ptr<Text>>      TextMap;
void Foo::setUpGame()
{
    mTextMap["MainText"] = std::make_unique<Text>(1,2,3,4); //create object on the heap an store a pointer to it in the map
}

一旦地图被破坏,std::unique_ptr将自动销毁文本对象。

如果由于某种原因你真的需要有一个原始指针的地图,你可以使用&#34; new&#34;正如David所解释的那样,但是当你不再使用它们时别忘了删除它们--c ++没有垃圾收集器(比如java)可以自动处理它。 / p>

答案 1 :(得分:1)

当您为对象动态分配内存时,只要您没有从内存中显式删除它,它就会存在,在您退出创建它的方法后它不会被删除,因此您可以在其中放置指针一张地图,它将永远存在(只需确保从地图中删除对象时删除内存)。

您可以使用以下简单代码对其进行测试,其中我在函数中声明一个新的Int,返回指向内存的指针并将其打印在接收映射的另一个函数中(其中包含指针)。它打印正确,这意味着即使超出范围也不会释放内存。

#include <iostream>
#include <map>

std::map<std::string, int*> myMap(){
    int* test = new int(1);

    std::map<std::string, int*> ObjMap;
    ObjMap["object"] = test;

    return ObjMap;
}

int main(int argc, const char * argv[]) {
    // insert code here...
    std::map<std::string, int*> mmap = myMap();

    std::cout << *mmap["object"] << std::endl;
    return 0;
}

所以要回答你的问题,请动态创建你的对象:

Obj* obj = new obj(1,2,3,4);

超出范围时不会删除。尽管如此,除非你使用智能指针,否则你需要自己删除内存,如下所示:delete obj;(当你从地图中删除它时,释放内存,因为它不会自动释放)。

PS:您应该阅读堆栈和堆的工作原理以及动态和静态分配的工作原理(使用堆栈或堆)。 See this c++ dynamic memory allocation tutorial to have more informations.

MikeMB 所说,使用智能指针更容易,因为您确定删除了内存,并且您也确定永远不会访问已删除的内存。有关智能指针信息,请参阅此Stack Overflow主题:What is a smart pointer and when should I use one?

答案 2 :(得分:1)

&#34; text&#34; setUpGame完成后,对象将超出范围。此时,堆内存被释放,以便被堆的任何新用途覆盖。它本质上是项的临时暂存器,它只存在于函数的范围内(或者在函数内的显式范围操作符中)。

David G的建议是合理的:阅读更多关于堆栈和堆内存之间的区别,并考虑使用智能指针的建议。但是,如果您想要对您当前的问题进行廉价,肮脏的修复,可以试试这个:

void Foo::setUpGame()
{
    static Text text(1,2,3,4); // Note use of "static" keyword
    mTextMap["MainText"] = &text; //save it in the map!
}

虽然我并不主张使用静态作为解决更基本的架构内存问题的捷径,但如果您急于让事情发挥作用,您可以将其作为一种短期措施。将对象标记为静态可确保其生命周期超出函数的范围。但我不建议将其作为这类问题的长期解决方案。