2015-12-17 56 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! 
} 

雖然我不主張用靜態的快捷方式,以解決更多的基本架構內存問題,您可以使用這是一個短期措施,如果你不顧一切地做事。將對象標記爲靜態可確保其生命週期將超過函數的範圍。但我不會推薦它作爲這類問題的長期解決方案。