2012-02-10 63 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