从映射中检索后,映射中的对象已损坏
Object in map corrupted after retrieving from the map
所以我已经完全编辑了我的问题。我有一个名为mTextMap
的map
,它包含:
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
已完全损坏!!
为什么会发生这种情况?
一般的问题似乎是,您认为这一行:
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
就会自动销毁文本对象。
如果出于某种原因,你真的需要一个原始指针的映射,你可以像David解释的那样使用"new",但当你不再使用它们时,不要忘记删除它们——c++没有垃圾收集器(比如java)可以自动处理这件事。
一旦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!
}
虽然我不主张使用静态作为解决更基本的体系结构内存问题的捷径,但如果你迫切想让事情正常运行,你可以将其作为短期措施。将对象标记为静态可确保其生存时间超过函数的作用域。但我不建议将其作为这类问题的长期解决方案。
当您为对象动态分配内存时,只要您没有明确地将其从内存中删除,它就会一直存在,在您退出创建它的方法后,它不会被删除,所以您可以将指向它的指针放在映射中,它将一直存在(只需确保从映射中删除对象时删除内存)。
你可以用下面的简单代码来测试这一点,我在一个函数中声明一个新的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;
(当您从映射中删除它时,释放内存,因为它不会自动释放)。
附言:您应该阅读堆栈和堆的工作原理,以及动态和静态分配的工作原理(使用堆栈或堆)。请参阅本c++动态内存分配教程以获得更多信息。
正如MikeMB所说,使用智能指针更容易,因为你可以确保删除了内存,也可以确保永远不会访问已删除的内存。有关智能指针的信息,请参阅此堆栈溢出主题:什么是智能指针,何时应该使用智能指针?
- 使用std::函数映射对象方法
- 使用"std::unordereded_map"映射到"std::list"对象
- 在c++中访问int到类对象的映射时出错
- 如何创建对象函数指针C++映射?
- 准确了解对象在内存中的映射方式
- 将包含不可复制对象的对插入到映射中
- 用unordered_map映射对象作为键
- 如何通过文件映射对象重新映射共享内存的视图?
- 文件映射对象和文件对象可以互换使用吗
- 如何从 std::映射'm'对象中返回 Iter 以'n'选定对象 (c++)
- 包含抽象基类ptr_map的映射对象
- C++ 映射对象的顺序
- 更新标准::映射对象数据
- C++ 内存泄漏与我的 std::映射 &对象和标准::矢量 &对象
- Windows CreateFileMapping:具有相同支持文件的不同文件映射对象
- 使用C++中的文件映射对象进行读取
- c++构造函数映射对象(已编辑)
- 在映射对象上定义自定义迭代器:神秘的"incomplete type"错误
- 在(c++) cocos2dx中添加映射对象到Vector
- c++代码中共享文件映射对象大小的问题