2016-03-17 8 views
2

Я пытался обернуть вокруг головы полиморфизма в C++ Из того, что я понимаю, она идет, как этотC++ - Утечка памяти и полиморфизм

class Base { 
//... 
public: 
    virtual int Foo() {...} = 0; 
}; 
//... 
class Derived: public Base { //Could be protected or private as well 
//... 
public: 
    int Foo() {...} 
}; 

Я также знаю, что, когда у нас есть массив динамически распределяемой объектов, мы должны вызвать delete [] arr в конце программы после удаления каждой отдельной записи массива.

Так что, когда я запускаю следующую программу, я не знаю, почему я получаю утечку памяти

#include <iostream> 
using namespace std; 

class Number { 
public: 
    ~Number() { 
    cout << "Expression deleted" << endl; 
    } 
virtual void print() = 0; 
}; 

class Int: public Number { 
private: 
    int num; 
public: 
    Int(int n) { 
    num = n; 
    } 
    void print() { 
    cout << "Num: " << num << endl; 
    } 
    ~Int() { 
    cout << "Number deleted" << endl; 
    } 
}; 

int main() { 
Number *arr[10]; 
arr[0] = new Int(1); 
arr[1] = new Int(2); 
arr[2] = new Int(3); 

arr[0]->print(); 
arr[1]->print(); 
arr[2]->print(); 

delete arr[0]; 
delete arr[1]; 
delete arr[2]; 
delete [] arr; 
} 

Это первый дает мне предупреждение при компиляции

poly.cc: In function 'int main()': 
poly.cc:37:12: warning: deleting array 'Number* arr [10]' [enabled by default] 

Тогда, когда я его запускаю , это дает мне это

Num: 1 
Num: 2 
Num: 3 
Expression deleted 
Expression deleted 
Expression deleted 
*** glibc detected *** ./a.out: munmap_chunk(): invalid pointer: 0x00007fff785732d0 *** 
======= Backtrace: ========= 
/lib/x86_64-linux-gnu/libc.so.6(+0x7db26)[0x7f9274641b26] 
./a.out[0x400b07] 
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xed)[0x7f92745e576d] 
./a.out[0x400959] 
======= Memory map: ======== 
00400000-00401000 r-xp 00000000 00:32 43144247       
00601000-00602000 r--p 00001000 00:32 43144247       
00602000-00603000 rw-p 00002000 00:32 43144247       
01b5f000-01b91000 rw-p 00000000 00:00 0         [heap] 
7f92740b1000-7f92740c7000 r-xp 00000000 fc:00 50593804     /lib/x86_64-linux-gnu/libgcc_s.so.1 
7f92740c7000-7f92742c6000 ---p 00016000 fc:00 50593804     /lib/x86_64-linux-gnu/libgcc_s.so.1 
7f92742c6000-7f92742c7000 r--p 00015000 fc:00 50593804     /lib/x86_64-linux-gnu/libgcc_s.so.1 
7f92742c7000-7f92742c8000 rw-p 00016000 fc:00 50593804     /lib/x86_64-linux-gnu/libgcc_s.so.1 
7f92742c8000-7f92743c3000 r-xp 00000000 fc:00 50602224     /lib/x86_64-linux-gnu/libm-2.15.so 
7f92743c3000-7f92745c2000 ---p 000fb000 fc:00 50602224     /lib/x86_64-linux-gnu/libm-2.15.so 
7f92745c2000-7f92745c3000 r--p 000fa000 fc:00 50602224     /lib/x86_64-linux-gnu/libm-2.15.so 
7f92745c3000-7f92745c4000 rw-p 000fb000 fc:00 50602224     /lib/x86_64-linux-gnu/libm-2.15.so 
7f92745c4000-7f9274778000 r-xp 00000000 fc:00 50602238     /lib/x86_64-linux-gnu/libc-2.15.so 
7f9274778000-7f9274977000 ---p 001b4000 fc:00 50602238     /lib/x86_64-linux-gnu/libc-2.15.so 
7f9274977000-7f927497b000 r--p 001b3000 fc:00 50602238     /lib/x86_64-linux-gnu/libc-2.15.so 
7f927497b000-7f927497d000 rw-p 001b7000 fc:00 50602238     /lib/x86_64-linux-gnu/libc-2.15.so 
7f927497d000-7f9274982000 rw-p 00000000 00:00 0 
7f9274982000-7f9274a84000 r-xp 00000000 fc:00 41962840     /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21 
7f9274a84000-7f9274c83000 ---p 00102000 fc:00 41962840     /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21 
7f9274c83000-7f9274c8b000 r--p 00101000 fc:00 41962840     /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21 
7f9274c8b000-7f9274c8d000 rw-p 00109000 fc:00 41962840     /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21 
7f9274c8d000-7f9274c90000 rw-p 00000000 00:00 0 
7f9274c90000-7f9274cb2000 r-xp 00000000 fc:00 50602228     /lib/x86_64-linux-gnu/ld-2.15.so 
7f9274e84000-7f9274e89000 rw-p 00000000 00:00 0 
7f9274eae000-7f9274eb2000 rw-p 00000000 00:00 0 
7f9274eb2000-7f9274eb3000 r--p 00022000 fc:00 50602228     /lib/x86_64-linux-gnu/ld-2.15.so 
7f9274eb3000-7f9274eb5000 rw-p 00023000 fc:00 50602228     /lib/x86_64-linux-gnu/ld-2.15.so 
7fff78553000-7fff78574000 rw-p 00000000 00:00 0       [stack] 
7fff785c7000-7fff785c9000 r-xp 00000000 00:00 0       [vdso] 
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0     [vsyscall] 
Aborted 

Кажется, что объекты добавляются и удаляются успешно. Я не вижу, что случилось.

ответ

6

Здесь есть две проблемы. Во-первых, это недействительно:

delete [] arr; 

arr не new[] был -ed так что не нужно быть delete[] -ed. arr находится только в стеке. Вот почему ваш компилятор дал вам предупреждение! (clang прямо вверх ошибки). Хорошее эмпирическое правило - не игнорировать предупреждения компилятора.

Вторая проблема здесь:

~Number() { 
    cout << "Expression deleted" << endl; 
} 

delete Когда вы Number, ~Number() будет выполнена, и что память будет освобождена до ... но не ~Int(). Вам нужно сделать деструктор virtual, если вы собираетесь удалить указатели базового класса. Это должен был во главе с предупреждением, а что-то вроде:

main.cpp: In function 'int main()': 
main.cpp:37:14: warning: deleting object of abstract class type 'Number' which has non-virtual destructor will cause undefined behaviour [-Wdelete-non-virtual-dtor] 
    delete arr[0]; 
      ^
+0

Спасибо. Я не получил эту ошибку, о которой вы говорили в конце. Однако я сделал destrucor виртуальным и удалил delete [] arr. Он работает сейчас. Только вопрос о последующей деятельности. Когда я запускаю код, он выглядит так, как сначала вызывается Int destructor, затем вызывается Number destructor для каждого объекта в массиве. Почему деструктор нужно вызывать дважды? Еще раз спасибо. –

+0

@Q_A Ничто не называется дважды. То, что вы видите, - это производный подобъект, который уничтожается перед базовым подобъектом ... все нужно уничтожить. – Barry

+0

@Q_A Кроме того, не редактируйте ответы на свои вопросы. Вы можете указать ответы, которые помогли вам, приняв их (см. [Тур]). – Barry

1

Потому что для каждого класса polymoprhic вам нужно определить виртуальный деструктор. В противном случае удаление производного класса с помощью указателя на базовый класс не вызовет деструктор производного класса.