2017-08-06 53 views
0

我正在使用valgrind來嘗試修復我正在處理的賦值中的許多內存泄漏,並且它給了我幾個不同的讀/寫/未初始化值錯誤。我認爲我知道基於valgrind輸出它來自哪裏,但不知道如何解決它爲我的生活。我對C++很陌生,所以我可能只是做了一些完全不正確的事情,我如何分配(然後試圖訪問錯誤分配的內存)數組的內存,但我無法弄清楚究竟是什麼將會。Valgrind:無效的寫入大小8來自複製構造函數

這裏的各種Valgrind的輸出:

Invalid write of size 8 
==13371== at 0x4013F5: family::setFriends(char**) (family.cpp:62) 
==13371== by 0x4: family::family(family const&) (family.cpp:31) 
==13371== by 0x402358: hashtable::node::node(family const&) (hashtable.h:29) 
==13371== by 0x401E81: hashtable::insert(char const*, family const&) (hashtable.cpp:87) 
==13371== by 0x4018CD: familymgr::addFamily(family&) (familymgr.cpp:15) 
==13371== by 0x402779: main (housinghelper.cpp:86) 
==13371== Address 0x5ad1810 is 0 bytes inside a block of size 32 free'd 
==13371== at 0x4C2F650: operator delete[](void*) (vg_replace_malloc.c:621) 
==13371== by 0x4013B5: family::setFriends(char**) (family.cpp:60) 
==13371== by 0x4: family::family(family const&) (family.cpp:31) 
==13371== by 0x402358: hashtable::node::node(family const&) (hashtable.h:29) 
==13371== by 0x401E81: hashtable::insert(char const*, family const&) (hashtable.cpp:87) 
==13371== by 0x4018CD: familymgr::addFamily(family&) (familymgr.cpp:15) 
==13371== by 0x402779: main (housinghelper.cpp:86) 
==13371== Block was alloc'd at 
==13371== at 0x4C2E8BB: operator new[](unsigned long) (vg_replace_malloc.c:423) 
==13371== by 0x40120F: family::family(family const&) (family.cpp:29) 
==13371== by 0x402358: hashtable::node::node(family const&) (hashtable.h:29) 
==13371== by 0x401E81: hashtable::insert(char const*, family const&) (hashtable.cpp:87) 
==13371== by 0x4018CD: familymgr::addFamily(family&) (familymgr.cpp:15) 
==13371== by 0x402779: main (housinghelper.cpp:86) 

未初始化的值的消息:

Use of uninitialised value of size 8 
==13371== at 0x401E98: hashtable::insert(char const*, family const&) (hashtable.cpp:90) 
==13371== by 0x4018CD: familymgr::addFamily(family&) (familymgr.cpp:15) 
==13371== by 0x402779: main (housinghelper.cpp:86) 
==13371== Uninitialised value was created by a stack allocation 
==13371== at 0x401882: familymgr::addFamily(family&) (familymgr.cpp:11) 
==13371== 
==13371== Use of uninitialised value of size 8 
==13371== at 0x401EB9: hashtable::insert(char const*, family const&) (hashtable.cpp:91) 
==13371== by 0x4018CD: familymgr::addFamily(family&) (familymgr.cpp:15) 
==13371== by 0x402779: main (housinghelper.cpp:86) 
==13371== Uninitialised value was created by a stack allocation 
==13371== at 0x401882: familymgr::addFamily(family&) (familymgr.cpp:11) 

'朋友' 是在頭文件作爲如此宣佈一個char **成員變量:

char **friends; 

一切似乎都來自複製構造函數:

family::family(const family &fam) : ID(NULL), famName(NULL), 
friends(NULL){ 
    setID(fam.ID); 
    setFamName(fam.famName); 
    setMembers(fam.members); 
    setCapacity(fam.capacity); 
    setNumFriends(fam.numFriends); 

    setFriends(fam.friends); 
} 

這裏是主要的構造,只是櫃面我沒有正確的friends權從分配內存開始走:

family::family(char *ID, char *famName, int members) : 
    ID(NULL), 
    famName(NULL), 
    members(members), 
    numFriends(-1), 
    capacity(DEFAULT_CAPACITY) 
{ 
    friends = new char*[capacity]; 
    for (int i = 0; i < numFriends; i++) 
     friends[i] = NULL; 

    setID(ID); 
    setFamName(famName); 
} 

這裏是正在被引用的setFriends功能:

void family::setFriends(char** friendIn){ 
friends = new char*[sizeof(friendIn[0])/numFriends]; 
if(friends!=NULL) 
    delete [] friends; 
for (int i = 0; i < capacity;i++){ 
    this->friends[i] = friendIn[i]; 
    } 
} 

bool familymgr::addFamily(family &inputFam) { 
    char fam[100]; 
    inputFam.getID(fam); 

    table->insert(fam, inputFam); 
} 

的getID:

void family::getID(char *id) const { 
    strcpy(id, this->ID); 
} 

我在這裏做錯了什麼來產生所有這些錯誤?

+0

那些valgrind錯誤不描述泄漏。首先關注第一個錯誤 - 是你發佈的第一個錯誤? – aschepler

+0

@aschepler是我的錯誤。我說泄漏,因爲我確實有大量內存泄漏,但我認爲內存泄漏來自我發佈的錯誤。 – ThomasJazz

+0

'addFamily'的代碼在哪裏? – 1201ProgramAlarm

回答

0

無效寫入來自setFriends,您刪除分配給friends的內存然後寫入它。在朋友複製之前,您需要在setFriends中進行新分配。

因爲在family構造函數中有兩個名爲ID的變量:參數和類成員,所以會出現未初始化的值消息。當你調用setID(ID)時,這是引用類成員(值爲NULL),而不是參數ID。將這些參數重命名爲與該類中的字段具有不同的名稱。

+0

'除非我誤解,我是不是已經爲'friends = new char * [sizeof(fam.friends [0])/ numFriends];'在拷貝構造函數中爲'friends'做了一個新的分配? – ThomasJazz

+0

這是在構造函數中。該內存在'setFriends'中用'delete [] friends'被刪除(釋放),並且您需要分配新的內存才能再次使用它。 – 1201ProgramAlarm

+0

@ThomasJazz'delete [] friends'後面立即引用,即:'this-> friends [i] = ...'是一個未定義行爲的* recipe。事實上,它是有保證的。閱讀文字中的動態對象生命週期。 – WhozCraig

0

setFriends方法寫入你沒有自己的記憶:

void family::setFriends(char** friendIn){ 
    friends = new char*[sizeof(friendIn[0])/numFriends]; 
    if(friends!=NULL) // <-- This will always be true, since friends was 
         //  assigned a non-null value in the new[] 
         //  expression above 
     delete [] friends; // <-- Here you free the memory you just allocated 
    for (int i = 0; i < capacity;i++){ 
     // At this point, friends is no longer pointing to a valid object 
     // so you are trying to write to memory you don't own 
     this->friends[i] = friendIn[i]; 
    } 
} 

你應該扭轉對NULL檢查和new[]表達。另外,使用sizeof(friendIn[0])/numFriends是沒有意義的。 sizeof(friendIn[0]將始終爲4或8,具體取決於您的平臺的位數。我猜應該只是capacity

void family::setFriends(char** friendIn){ 
    if(friends != nullptr) { 
     delete [] friends; 
    } 
    friends = new char*[capacity]; 
    for (int i = 0; i < capacity;i++){ 
     this->friends[i] = friendIn[i]; 
    } 
} 

從拷貝構造函數調用時這是可行的,但要記住,你還在做的friends淺拷貝。family這兩個對象都將指向相同的字符串,並且如果以後這些字符串delete[]那麼仍然指向它們的任何對象都不起作用。你應該真的只是讓friends a std::vector<std::string>>而不是做所有這些手動內存管理。那麼你可以使setFriends更簡單,更安全:

void family::setFriends(std::vector<std::string>> friendIn) { 
    friends = std::move(friendIn); 
}