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

C++ 从地图检索后,地图中的对象已损坏,c++,c++11,C++,C++11,所以我完全编辑了我的问题。 我有一个名为mTextMap的map包含: typedef std::map<const std::string, Text*> TextMap; TextMap mTextMap; 现在如果我用这种方式: Foo foo; foo.setUpGame(); Text& myText = foo.getText("MainText"); // Why is this corrupted? 对象myText已完全损坏 为什么会发生这种

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

typedef std::map<const std::string, Text*>      TextMap;
TextMap mTextMap;
现在如果我用这种方式:

Foo foo;
foo.setUpGame();

Text& myText = foo.getText("MainText"); // Why is this corrupted?
对象
myText
已完全损坏


为什么会发生这种情况?

当您为对象动态分配内存时,只要您不从内存中显式删除它,它就会一直存在,退出创建它的方法后它不会被删除,因此您可以在映射中放置指向它的指针,并且它将始终存在(从地图中删除对象时,请确保删除内存)

您可以用下面的简单代码来测试这一点,我在一个函数中声明了一个新的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;
}
当超出范围时,它不会被删除。但是,除非您使用智能指针,否则您需要自己删除内存,如:
delete obj;
(当您从映射中删除它时,释放内存,因为它不会自动释放)

PS:您应该了解堆栈和堆是如何工作的,以及动态和静态分配是如何工作的(使用堆栈或堆)


正如MikeMB所说,使用智能指针更容易,因为您可以确保删除了内存,也可以确保永远不会访问已删除的内存。有关智能指针的信息,请参阅此堆栈溢出主题:

当您为对象动态分配内存时,只要您不显式删除,它就会存在从内存中删除它,在退出创建它的方法后,它不会被删除,因此您可以在映射中放置指向它的指针,并且它将始终存在(只需确保在从映射中删除对象时删除内存)

您可以用下面的简单代码来测试这一点,我在一个函数中声明了一个新的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;
}
当超出范围时,它不会被删除。但是,除非您使用智能指针,否则您需要自己删除内存,如:
delete obj;
(当您从映射中删除它时,释放内存,因为它不会自动释放)

PS:您应该了解堆栈和堆是如何工作的,以及动态和静态分配是如何工作的(使用堆栈或堆)

正如MikeMB所说,使用智能指针更容易,因为您可以确保删除了内存,也可以确保永远不会访问已删除的内存。有关智能指针的信息,请参阅此堆栈溢出主题:

“文本”对象将在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!
}
虽然我不主张使用静态作为解决更基本的体系结构内存问题的捷径,但如果您非常想让事情正常工作,可以将其作为短期措施。将对象标记为静态可确保其生命周期超过功能范围。但我不建议将其作为解决问题的长期解决方案这类问题。

setUpGame一完成,“text”对象就超出范围。此时,堆内存被释放出来,以供堆的任何新用途覆盖。它本质上是一个临时草稿行,只存在于函数范围内(或函数内显式范围运算符内)

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!
}

虽然我不主张使用静态作为解决更基本的体系结构内存问题的捷径,但如果您非常想让事情正常工作,可以将其作为短期措施。将对象标记为静态可确保其生命周期超过功能范围。但我不建议将其作为解决问题的长期解决方案他的问题。

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

mTextMap["MainText"] = &text;
将文本对象存储在映射中。它不会!它在映射中存储指向该对象的指针,并且文本对象本身(正如您自己所说)将在函数结束时自动销毁。因此,现在您的指针指向一个不存在的对象,这将导致观察到的错误

对于你的问题,有各种各样的解决方案,具体取决于你想要达到的目标,以及你将在课堂上做什么

一种可能性是使用文本对象的映射(而不是指针):

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

typedef std::map TextMap;
void Foo::setUpGame()
{
mTextMap[“MainText”]=std::make_unique(1,2,3,4);//在堆上创建对象并在映射中存储指向该对象的指针
}
地图一被销毁,
std::unique_ptr
就会自动销毁文本对象


<>如果你真的需要某种原因的原始指针映射,你可以使用戴维解释的“新”,但是不要忘记在你不再使用它们时——C++没有垃圾收集程序(比如java),这样会自动处理这个问题。
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
}
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
}