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
}