2015-12-17 55 views
0

取回后损坏的所以我已经编辑完成我的问题。 我有一个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完全损坏!

这是怎么发生的?

+1

使用['unique_prt'](http://www.cplusplus.com/reference/memory/unique_ptr/)或['shared_prt'](http://www.cplusplus.com/reference/memory/shared_ptr/ )作为地图中的值类型。如果你是自己管理记忆,那很容易犯错。 –

+1

如果您愿意,我们检查了您的代码,提供[最小,完整和可验证示例](http://stackoverflow.com/help/mcve)。 –

+2

你为什么要存储指向objs而不是obj本身的指针? – MikeMB

回答

2

普遍的问题似乎是,你认为这行:

mTextMap["MainText"] = &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会自动销毁文本对象,一旦地图被破坏。

如果你真的需要有一个原始指针的地图出于某种原因,你可以使用“新”大卫解释,但不要忘记删除它们时,不再使用它们 - C++ doesn'没有垃圾收集器(如Java)会自动处理这个问题。

+0

为什么不只是'std :: map '? – Danh

+0

@Danh:这就是我正在做的,不是? – MikeMB

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说,使用智能指针是容易,因为你一定会删除你的记忆,你也一定会你从来没有访问已删除的记忆。查看智能指针信息的堆栈溢出主题:What is a smart pointer and when should I use one?

+1

我真的试图避免新的和删除,除非它提供了一个真正的好处与使用智能指针相比。 – MikeMB

+1

我认为这个问题更多的是如何确保内存在超出范围时不会被删除,所以我认为解释动态分配更重要。不过,使用智能指针是一个更安全的好主意。 –

+1

我的观点是不显示一个解决方案,它包含原始的指针 - 特别是没有解释对象不再需要手动删除它们。 – MikeMB

1

setUpGame完成后,“文本”对象即将超出范围。此时,堆内存将被任何新的堆使用覆盖。它实质上是一个临时的暂存器,它只存在于函数的范围内(或者在函数内部的显式范围操作符内)。

大卫G公司的建议十分合理:了解更多有关栈和堆内存之间的差异,并考虑使用智能指针的建议。但是,如果你想要一个便宜的,肮脏的修复,以立即解决问题,你可以试试这个:

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

虽然我不主张用静态的快捷方式,以解决更多的基本架构内存问题,您可以使用这是一个短期措施,如果你不顾一切地做事。将对象标记为静态可确保其生命周期将超过函数的范围。但我不会推荐它作为这类问题的长期解决方案。