2013-05-13 2 views
-1

Я изменяю размер и массив объектов. Я создал временный объект, но когда я его не удаляю, Valgrind показывает утечки памяти и ошибку. Удаление его вызывает segfault. Просто интересно, что Valgrind жалуется ...Не удается удалить временный объект

void Obj::resize() 
{ 
    Obj *temp = new Obj[size * 2]; //<-- line 92 
    for (int i = 0; i < size; i++) 
    temp[i] = objarray[i]; 
    delete [] objarray; 
    objarray = temp; 
    size *= 2; 
    //delete temp; //<-- causes segfault 
    //delete [] temp; // also segfaults, tried them both just in case :\ 
} 

Вот отчет Valgrind:

==9292== HEAP SUMMARY: 
==9292==  in use at exit: 21,484 bytes in 799 blocks 
==9292== total heap usage: 3,528 allocs, 2,729 frees, 91,789 bytes allocated 
==9292== 
==9292== 21,484 (2,644 direct, 18,840 indirect) bytes in 1 blocks are definitely lost in loss record 4 of 4 
==9292== at 0x4008409: operator new[](unsigned int) (vg_replace_malloc.c:357) 
==9292== by 0x804AC7E: MyClass::resize() (file.cpp:92) 
==9292== by 0x804AC34: MyClass::add(int, int) (file.cpp:82) 
==9292== by 0x804AAE6: getline(std::istream&, MyClass&) (file.cpp:66) 
==9292== by 0x8049772: main (otherfile.cpp:39) 
==9292== 
==9292== LEAK SUMMARY: 
==9292== definitely lost: 2,644 bytes in 1 blocks 
==9292== indirectly lost: 18,840 bytes in 798 blocks 
==9292==  possibly lost: 0 bytes in 0 blocks 
==9292== still reachable: 0 bytes in 0 blocks 
==9292==   suppressed: 0 bytes in 0 blocks 
==9292== 
==9292== For counts of detected and suppressed errors, rerun with: -v 
==9292== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0) 

Я не слишком хорошо с БГД, но получил эту трассировку:

(gdb) run 
Starting program: 

Program received signal SIGSEGV, Segmentation fault. 
0x46ed40e3 in free() from /lib/libc.so.6 
Missing separate debuginfos, use: debuginfo-install glibc-2.15-58.fc17.i686 libgcc-4.7.2-2.fc17.i686 libstdc++-4.7.2-2.fc17.i686 
(gdb) backtrace 
#0 0x46ed40e3 in free() from /lib/libc.so.6 
#1 0x4742dba0 in operator delete(void*)() from /lib/libstdc++.so.6 
#2 0x0804ad68 in MyClass::resize (this=0xbffff28c) at file.cpp:98 
#3 0x0804ac35 in MyClass::add (this=0xbffff28c, month=10, day=31) 
    at file.cpp:82 
#4 0x0804aae7 in getline (input=..., a=...) at file.cpp:66 
#5 0x08049773 in main (argc=1, argv=0xbffff344) at otherfile.cpp:39 
(gdb) 

Я думаю, что удаление этого плохо, потому что это должно просто оставить указатель свисающим, поэтому меня не удивляет, что я получаю segfault. Тем не менее, почему это может вызвать проблемы с памятью? Любые идеи очень приветствуются.

+4

Зачем вам удаляться 'temp'? ** Вы не должны **. delete не освобождает указатель, а указывает на то, на что он указывает. Если вы удаляете 'temp', вы также удаляете свой' objarray' (* то, что он указывает на *). – stardust

+0

Да, я это понимаю. Мне интересно, почему это все еще создает проблему с памятью? – mcallinder

+0

Segfault может быть вызвано чем-то другим. Вы видите эффект там. Но причина может быть в добавлении ... – stardust

ответ

1

Действительно, вы не можете удалить его там, поскольку вы назначили его objarray, который будет использоваться позже.

Скорее всего, вы не удаляете objarray в деструкторе; или какая-либо другая функция переназначает его, не удаляя сначала первый массив.

Я бы использовал std::vector, а не ручной набор, чтобы позаботиться о освобождении для меня.

+0

Спасибо. Как вы (и другие) предложили, я пренебрегаю использовать деструктор правильно. – mcallinder

0

Явный delete (или delete[]) должен быть необходим только в очень низкоуровневом библиотечном коде. Вместо этого вы должны использовать интеллектуальные указатели.

Вот лучший подход, который (ИМО) легче понять:

std::unique_ptr<Obj[]> temp(new Obj[size * 2]); 

// copy stuff from objarray to temp 

swap(objarray, temp); 

Вот и все. Дескриптор unique_ptr освободит старый буфер objarray, если смена завершилась успешно. И если во время копирования было выбрано исключение, он освободит новый временный буфер. В любом случае objarray (который также должен быть std::unique_ptr<Obj[]>) остается с допустимым буфером.

+0

. Использование 'std :: unique_ptr', вероятно, является самым простым решением здесь, но я не думаю, что' swap' будет работать; оба аргумента 'swap' должны иметь один и тот же тип. (В общем, конечно: он в основном переопределяет 'std :: vector' и делает это правильно в общем случае --- например, если' Obj' не поддерживает конструкцию по умолчанию, является нетривиальной.) –

+0

@James: Естественно, 'objarray' также должен быть' unique_ptr '... нет никакой причины, чтобы он был необработанным указателем. –

+0

@Sarien: Он просто меняет указатели. Так что теперь 'temp' владеет старым буфером, который нужно уничтожить, и делает это, когда он выходит из области видимости в закрывающей скобке' resize'. –

0

Если это второй (или позже) вызове resize, то это очень вероятный сценарий, потому что вы пытаетесь delete на куче, которая уже имела double delete поскольку temp уже была удалена, и теперь все ваши записи objArray перешли в кучу памяти, которая принадлежит управлению кучей, а не вашему коду.

Здесь могут произойти всевозможные другие потенциальные проблемы, такие как память в настоящее время используется для некоторого ДРУГОГО объекта, и он записывает вещи в память кучи, которые затем используются как objArray.

Нельзя удалять temp, где вы пытаетесь это сделать. Только не надо.

Смежные вопросы