2017-08-06 26 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); 
}