简体   繁体   English

priority_queue的问题-堆之后写入内存

[英]Problem with priority_queue - Writing memory after heap

I am trying to use priority_queue, and program constantly fails with error message HEAP CORRUPTION DETECTED. 我正在尝试使用priority_queue,并且程序不断失败,并显示错误消息HEAP CORRUPTION DETECTED。

here are the snippets: 以下是片段:

class CQueue { ...
              priority_queue<Message, deque<Message>, less<deque<Message>::value_type> > m_messages;
...};

class Message has overloaded operators > and < 类Message具有重载的运算符>和<

Here I fill up queue: 在这里,我填满队列:

CQueue & operator+=(Message &rhv)
{
    m_messages.push(rhv);  //This is where program fails
    return *this;
}

and in the main program: 在主程序中:

string str;
CQueue pq;
for(int i = 0; i < 12; ++i)
{
    cin >> str;

    Message p(str.c_str(), rand()%12); //Create message with random priority
    pq += p;                           //add it to queue
}

I have no idea what seems to be the problem. 我不知道这是什么问题。 It happens when I push about 8 items, and it fails on line 当我推送约8个项目时,它会发生,并且在线失败

    push_heap(c.begin(), c.end(), comp);

in < queue > 在<队列>中

:( :(

Here is the definition of message class - it's very simple: 这是消息类的定义-非常简单:

#pragma once 

#include <iostream>
#include <cstring>
#include <utility>

using namespace std;

 class Poruka
{
private:
char *m_tekst;
int  m_prioritet;
public:
Poruka():m_tekst(NULL), m_prioritet(-1){}

Poruka(const char* tekst, const int prioritet)
{
    if(NULL != tekst)
    {
    //  try{
            m_tekst = new char[strlen(tekst) + 1];
        //}
        //catch(bad_alloc&)
    //  {
    //      throw;
    //  }


        strcpy(m_tekst, tekst);
    }
    else
    { 
    //  try
    //  {
            m_tekst = new char[1];
    //  }
    //  catch(bad_alloc&)
    //  {
    //      throw;
    //  }

        m_tekst[0] = '\0';
    }
    m_prioritet = prioritet;
}

Poruka(const Poruka &p)
{
    if(p.m_tekst != NULL)
    {
        //try
        //{
            m_tekst = new char[strlen(p.m_tekst) + 1];
        //}
        //catch(bad_alloc&)
        //{
        //  throw;
        //}

        strcpy(m_tekst, p.m_tekst);
    }
    else
    {
        m_tekst = NULL;
    }
    m_prioritet = p.m_prioritet;
}

~Poruka()
{
        delete [] m_tekst;
}

Poruka& operator=(const Poruka& rhv)
{
    if(&rhv != this)
    {
        if(m_tekst != NULL)
            delete [] m_tekst;

    //  try
        //{
            m_tekst = new char[strlen(rhv.m_tekst + 1)];
        //}
        //catch(bad_alloc&)
        //{
        //  throw;
        //}

        strcpy(m_tekst, rhv.m_tekst);
        m_prioritet = rhv.m_prioritet;
    }
    return *this;
}

friend ostream& operator<<(ostream& it, const Poruka &p)
{
    it << '[' << p.m_tekst << ']' << p.m_prioritet;
    return it;
}

//Relacioni operatori

friend inline bool operator<(const Poruka& p1, const Poruka& p2)
{
    return p1.m_prioritet < p2.m_prioritet;
}

friend inline bool operator>(const Poruka& p1, const Poruka& p2)
{
    return p2 < p1;
}

friend inline bool operator>=(const Poruka& p1, const Poruka& p2)
{
    return !(p1 < p2);
}

friend inline bool operator<=(const Poruka& p1, const Poruka& p2)
{
    return !(p1 > p2);
}

friend inline bool operator==(const Poruka& p1, const Poruka& p2)
{
    return (!(p1 < p2) && !(p2 < p1));
}

friend inline bool operator!=(const Poruka& p1, const Poruka& p2)
{
    return (p1 < p2) || (p2 < p1);
}

}; };

Poruka - Message Poruka-消息

I think the problem is that your Message objects are keeping pointers to raw C strings which are then getting deallocated. 我认为问题在于您的Message对象正在保留指向原始C字符串的指针,然后将其释放。 In these lines: 在这些行中:

cin >> str;

Message p(str.c_str(), rand()%12);

On each iteration of the loop, you're reading in a new value to str , which invalidates any old pointers returned by its c_str() method, so your older messages are pointing to invalid data. 在循环的每次迭代中,您都将读取一个新值str ,该值会使c_str()方法返回的所有旧指针无效,因此您的旧消息将指向无效数据。 You should change your Message object so that it stores its string as an std::string instead of a char* . 您应该更改Message对象,以便将其字符串存储为std::string而不是char* This will properly copy the string into the Message object. 这样可以将字符串正确复制到Message对象中。

Alternatively, if you can't change the Message class, you'll have to explicitly copy the string yourself, eg using strdup() or malloc() / new[] + strcpy() , and then you have to remember to deallocate the string copies at some later point. 另外,如果您不能更改Message类,则必须自己显式复制该字符串,例如,使用strdup()malloc() / new[] + strcpy() ,然后必须记得取消分配该字符串。在以后的某个时间点复制字符串。

I can't get it to fail. 我不能让它失败。
But there is not enough info to compile this line: 但是没有足够的信息来编译此行:

push_heap(c.begin(), c.end(), comp);

But the only problems I see are: 但是我看到的唯一问题是:

1) You have a default constructor that could create a Poruka with a NULL name: 1)您有一个默认构造函数,可以使用NULL名称创建一个Poruka:

Poruka::Poruka():m_tekst(NULL), m_prioritet(-1){}

2) Not a problem because you test for it most places but in the assignment operator you miss a test: 2)没问题,因为您测试了大多数地方,但是在赋值运算符中却错过了一个测试:

Poruka::Poruka& operator=(const Poruka& rhv)
{
 ....
    // There was no test for 'rhv.m_tekst' being NULL here.
    //
    m_tekst = new char[strlen(rhv.m_tekst + 1)];
    strcpy(m_tekst, rhv.m_tekst);

Notes: 笔记:

  • You could make your code much simpler by using the std::string class. 您可以使用std :: string类使代码更简单。
  • If you still want to use char* then if you gurantee it is never NULL then the code is simpler 如果您仍然想使用char *,那么如果您保证它永远不会为NULL,那么代码会更简单
  • Also there is a simpler patter for defining the standard copy constructor and assignment operator. 还有一个用于定义标准副本构造函数和赋值运算符的简单模式。 It is refered to as the copy/swap idium. 它被称为复制/交换Idium。
  • You dont need to define all those relational operators. 您不需要定义所有这些关系运算符。 There is a set of template ones that work automatically in see http://www.sgi.com/tech/stl/operators.html . http://www.sgi.com/tech/stl/operators.html中 ,有一组模板可以自动工作。 You just need to define operator< and operator== 您只需要定义operator <和operator ==

Here is an example of the copy/swap idium 这是复制/交换idium的示例

class X
{
     X(X const& copy)
     {
          // Do the work of copying the object
          m_tekst     = new char[strlen(copy.m_tekst) + 1];
          ...
          m_prioritet = copy.m_prioritet;
     }
     X& operator=(X const& copy)
     {
         // I like the explicit copy as it is easier to read
         // than the implicit copy used by some people (not mentioning names litb)
         //
         X  tmp(copy);  // Use the copy constructor to do the work

         swap(tmp);
     }
     void swap(X& rhs) throws ()
     {
         std::swap(this->m_tekst,   rhs.m_tekst);
         std::swap(this->prioritet, rhs.prioritet);
     }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM