2012-02-10 43 views
2

即使經過大量的研究,我仍然不知道爲什麼我從valgrind得到這個錯誤.. 有一個類的秒殺(它實現了一個僞雙鏈表)Valgrind無效的讀寫列表

class spike 
{ 
    int s_cell; 
    int s_begin; 
    int s_number; 
    int s_type; 
    spike *s_previous; 
    spike *s_next; 

    spike *s_origin; // pointer for original spike or itself 
        // (in the very first spike_data) 

    spike *s_derive; // pointer for the spike in the derived class 
        // (note, that sometimes there are 2 or more high 
        // order spike_data in parallel; the pointer is only to one) 
public: 
    spike(int c, int b, int n, int typ=c_normal) 
    { 
    s_cell = c; 
    s_begin = b; 
    s_number = n; 
    s_previous = NULL; 
    s_next = NULL; 
    s_derive = NULL; 
    s_origin = this; 
    s_type = typ; 
    } 

    ~spike() 
    { 
    kill(); 
    } 

和類spike_data。

class spike_data 
{ 
protected: 
    int sd_mode; 
    int sd_size; 
    int sd_number;  // the whole number of spikes 
    int sd_file;  // the number of files for analysis 
    int *sd_file_name; // the names of files used in the analysis 
    int sd_cells;  // the whole number of different cells 

    spike **sd_array; // array of all spikes 
    spike *sd_first[c_maxcells]; // array of the first entries of spikes 
    spike **sd_file_st; // spikes in array for indication of beginning of the new files 

// And here is the part that's getting the error 
// (it is happening when i try to release) 
void spike::kill() 
{ 
    // delete a cell from all references and t becomes "dead" 
    // actual release of memory is done in renumerate 
    try 
    { 
    if (s_previous != NULL) 
     s_previous->s_next = s_next; 
    if (s_next != NULL) 
     s_next->s_previous = s_previous; 
    if (s_origin && s_origin != this) 
    { 
     int tmp = 1; 
    while(tmp == 1) { 
     if (s_origin != NULL) { 
      if (s_origin->s_derive != NULL) { // LINE 674 
       if (s_origin->s_derive != this) { // LINE 675 
         s_origin=s_origin->s_derive; 
        } 
        else tmp = 0; 
       } 
      else tmp = 0;      
        } 
      else tmp = 0; 
    } 

     s_origin->s_derive=NULL; // LINE 685 
    } 
    } 
    catch (...) 
    { 
    } 
    s_next = NULL; 
    s_previous = NULL; 
    s_origin = NULL; 
} 


spike_data::~spike_data() 
{ 

if(sd_array!=NULL) 
{ 
    for(int i=0;i<sd_number;i++) 
     delete sd_array[i]; // LINE 697 

    delete[] sd_array; 
    sd_array=NULL; 
} 
if(sd_file_st!=NULL) 
{ 
    delete[] sd_file_st; 
    sd_file_st=NULL; 
} 
if(sd_file_name!=NULL) 
{ 
    delete[] sd_file_name; 
    sd_file_name=NULL; 
} 
} 

很抱歉,如果代碼是indigest,它不是我的,但它仍然是確定...

Invalid read of size 4 
==2079== at 0x806B0DF: spike::kill() (spikes.cpp:674) 
==2079== by 0x8067D26: spike::~spike() (spike.h:288) 
==2079== by 0x806B174: spike_data::~spike_data() (spikes.cpp:689) 
==2079== by 0x805CB1F: spike_anal::~spike_anal() (spikea.cpp:151) 
==2079== by 0x8061C1E: statistical_analysis(spike_group*, spike_data*) (spikeg.cpp:264) 
==2079== by 0x804B37E: calculate_something(int, int) (all.cpp:422) 
==2079== by 0x8059805: real_main(int, char const*) (simple.cpp:742) 
==2079== by 0x804DC20: main (hello.cpp:66) 
==2079== Address 0x5d8f534 is 28 bytes inside a block of size 32 free'd 
==2079== at 0x4023881: operator delete(void*) (vg_replace_malloc.c:387) 
==2079== by 0x806B17C: spike_data::~spike_data() (spikes.cpp:697) 
==2079== by 0x805CB1F: spike_anal::~spike_anal() (spikea.cpp:151) 
==2079== by 0x8061C06: statistical_analysis(spike_group*, spike_data*) (spikeg.cpp:264) 
==2079== by 0x804B37E: calculate_something(int, int) (all.cpp:422) 
==2079== by 0x8059805: real_main(int, char const*) (simple.cpp:742) 
==2079== by 0x804DC20: main (hello.cpp:66) 
==2079== 
==2079== Invalid read of size 4 
==2079== at 0x806B0EC: spike::kill() (spikes.cpp:675) 
==2079== by 0x8067D26: spike::~spike() (spike.h:288) 
==2079== by 0x806B174: spike_data::~spike_data() (spikes.cpp:689) 
==2079== by 0x805CB1F: spike_anal::~spike_anal() (spikea.cpp:151) 
==2079== by 0x8061C1E: statistical_analysis(spike_group*, spike_data*) (spikeg.cpp:264) 
==2079== by 0x804B37E: calculate_something(int, int) (all.cpp:422) 
==2079== by 0x8059805: real_main(int, char const*) (simple.cpp:742) 
==2079== by 0x804DC20: main (hello.cpp:66) 
==2079== Address 0x5d8f534 is 28 bytes inside a block of size 32 free'd 
==2079== at 0x4023881: operator delete(void*) (vg_replace_malloc.c:387) 
==2079== by 0x806B17C: spike_data::~spike_data() (spikes.cpp:697) 
==2079== by 0x805CB1F: spike_anal::~spike_anal() (spikea.cpp:151) 
==2079== by 0x8061C06: statistical_analysis(spike_group*, spike_data*) (spikeg.cpp:264) 
==2079== by 0x804B37E: calculate_something(int, int) (all.cpp:422) 
==2079== by 0x8059805: real_main(int, char const*) (simple.cpp:742) 
==2079== by 0x804DC20: main (hello.cpp:66) 
==2079== 
==2079== Invalid write of size 4 
==2079== at 0x806B10A: spike::kill() (spikes.cpp:685) 
==2079== by 0x8067D26: spike::~spike() (spike.h:288) 
==2079== by 0x806B174: spike_data::~spike_data() (spikes.cpp:689) 
==2079== by 0x805CB1F: spike_anal::~spike_anal() (spikea.cpp:151) 
==2079== by 0x8061C1E: statistical_analysis(spike_group*, spike_data*) (spikeg.cpp:264) 
==2079== by 0x804B37E: calculate_something(int, int) (all.cpp:422) 
==2079== by 0x8059805: real_main(int, char const*) (simple.cpp:742) 
==2079== by 0x804DC20: main (hello.cpp:66) 
==2079== Address 0x5d8f534 is 28 bytes inside a block of size 32 free'd 
==2079== at 0x4023881: operator delete(void*) (vg_replace_malloc.c:387) 
==2079== by 0x806B17C: spike_data::~spike_data() (spikes.cpp:697) 
==2079== by 0x805CB1F: spike_anal::~spike_anal() (spikea.cpp:151) 
==2079== by 0x8061C06: statistical_analysis(spike_group*, spike_data*) (spikeg.cpp:264) 
==2079== by 0x804B37E: calculate_something(int, int) (all.cpp:422) 
==2079== by 0x8059805: real_main(int, char const*) (simple.cpp:742) 
==2079== by 0x804DC20: main (hello.cpp:66) 

所以這裏。當我想殺spike_data時,每次我調用delete sd_array [i],它調用spike的析構函數=> kill() 最後是這個代碼錯誤。它在執行過程中多次使用,並且在所有計算完成並需要釋放內存時,它都不起作用。我認爲有問題的時候,我把s_origin-> s_derive = NULL。但不能抓住它...

如果u需要更多的代碼只是問:)

謝謝你很多關於那些誰有勇氣進入這個代碼!

好週末

尼科

+1

OMG請在發佈之前仔細閱讀您的代碼!我在編輯它 – Eregrith 2012-02-10 18:38:41

+0

不明白爲什麼代碼樣式不適用於類的第一行。抱歉。或者你在談論風格?是的,我同意這真的是一種折磨。我會試着將這段代碼改成更好看的..它來自俄羅斯^^ – Nikkolasg 2012-02-10 18:45:20

+0

我改變了它。這更好。 由於換行符缺席而失敗^^ – Eregrith 2012-02-10 18:51:56

回答

1

有一個很好的可能性,對於秒殺的默認的拷貝構造函數已經沒有你注意到它調用。如果是這種情況,第一個析構函數可能會正確運行,但第二次調用將導致valgrind轉儲您發佈的消息。

爲了看看是否是這樣的話,如果你使用的是C++ 11,地址:

public: 
    spike(const spike& rhs) = delete; 

您的代碼應編譯失敗,表明需要你寫自己的副本構造函數。

如果你是使用C++ 11的而不是,你可以編寫你自己的拷貝構造函數,並在裏面放置一個斷點,看它是否在調試時停在那裏。

+0

我已經創建了像這樣的spike :: spike(const spike&rhs){}的拷貝構造函數,但程序永遠不會停止,所以它不會調用任何拷貝構造函數...:/ thx無論如何! – Nikkolasg 2012-02-16 17:54:36

+0

原程序員使用大量的memcpy cmd(而不是複製構造函數:舊代碼)。例如:dop = new spike * [sd_size];的memcpy(DOP,sd_array,的sizeof(尖峯*)* sd_number);我會爲此努力,可能就是這樣。 – Nikkolasg 2012-02-16 18:06:30

+0

在spikes.cpp:689和spikes.cpp:697上放置斷點 - 當您點擊斷點時,打印出正在釋放的內存位置。然後將斷點更改爲條件斷點,以便當變量再次是該地址時停止。當它再次遇到這個問題時,請去看看堆棧,你會發現問題。你在這裏有一個確定性的內存錯誤 - 不應該很難調試(除非你的調用堆棧中有令人討厭的意大利麪代碼)。你將不得不用你的眼睛和大腦來抓這個。 – kfmfe04 2012-02-16 22:48:53