Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Общие вопросы > И снова очередь


Автор: webgraf 7.6.2007, 11:39
Выдает ошибку при запуске(конкретно - при добавлении в очередь). Вроде как проблемы с кучей(dbgheap.c). Как правильно организовать в очередь из блоков данных?

Код

#include <stdafx.h>
#include <stdio.h>
#include <conio.h>
#include <queue>

// структура данных:
struct pdata
{
    unsigned char * buf;
    unsigned int size;
    
    // конструктор
    pdata(unsigned char *b, unsigned int s)
    {
        buf = (unsigned char *)malloc(s);
        memcpy(buf,b,s);
        size = s;
    }
    // деструктор
    ~pdata()
    {
        free(buf);
    }
};


int main(int argc, char* argv[])
{
    unsigned char * buf1 = (unsigned char *)malloc(1000);
    // объявляется очередь
    std::queue <pdata> q;

    memset(buf1,120,600); // тестовые данные
    
    q.push(pdata(buf1, 600)); // пробуем добавить
    q.pop();                  // и выкинуть
   
    return 0;
}

Автор: Fazil6 7.6.2007, 12:02
удалено

Автор: webgraf 7.6.2007, 12:28
а вот со строками все просто работает:
Код

#include <stdafx.h>
#include <stdio.h>
#include <conio.h>
#include <queue>

// структура данных:
struct pdata
{
    char name[20];
    char depart[20];
    
    // конструктор
    pdata(char *n, char *d )
    {
        strcpy(name,n);
        strcpy(depart,d);
    }
};


int main(int argc, char* argv[])
{

    // объявляется очередь
    std::queue <pdata> q;
   
    q.push(pdata("test1","test2")); // пробуем добавить
    q.pop();                  // и выкинуть
   
    return 0;
}


Как с блоками данных быть?

Автор: Fazil6 7.6.2007, 12:34
Цитата(webgraf @  7.6.2007,  12:28 Найти цитируемый пост)
Как с блоками данных быть?

тебе нужен конструктор копии. Поумолчанию будет тупо копировать unsigned char * buf и потом при удалении твоих объектов pdata в деструкторе будет пытаться вызывать free 2 раза для одного и тогоже участка памяти
Код

struct pdata
{
    unsigned char * buf;
    unsigned int size;

    // конструктор

    pdata(unsigned char *b, unsigned int s)
    {
        buf = (unsigned char *)malloc(s);
        memcpy(buf,b,s);
        size = s;
    }

    pdata(const pdata &rhs  )
    {
        buf = (unsigned char *)malloc(rhs.size);
        memcpy(buf,rhs.buf,rhs.size);
        size = rhs.size;
    }
    // деструктор
    ~pdata()
    {
        free(buf);
    }
};

 

Автор: evGenie 7.6.2007, 12:37
А в строчке 
Код

q.push(pdata(buf1, 600));

ведь сначала создается объект (вызывается конструктор), а потом происходит вызов конструктора копий? Который, сгенерированный по умолчанию, в твоем случае не работает, т.к. память выделяется с помощью malloc(). Определи соответствующий конструктор и все.

Автор: korbian 7.6.2007, 12:39
Констрктор копирования и оператор присваивания переопредели

Автор: webgraf 7.6.2007, 13:29
Цитата(Fazil6 @  7.6.2007,  12:34 Найти цитируемый пост)
тебе нужен конструктор копии. Поумолчанию будет тупо копировать unsigned char * buf и потом при удалении твоих объектов pdata в деструкторе будет пытаться вызывать free 2 раза для одного и тогоже участка памяти

Т.е. теперь память выделяется при вызове конструтора копии?

Автор: korbian 7.6.2007, 13:38
Выделяешь новую память и копируешь в нее содержимое pdata::buf копируемого объекта.

Автор: Fazil6 7.6.2007, 14:29
Цитата(webgraf @  7.6.2007,  13:29 Найти цитируемый пост)
Т.е. теперь память выделяется при вызове конструтора копии?

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

Автор: webgraf 7.6.2007, 15:29
Цитата(Fazil6 @  7.6.2007,  14:29 Найти цитируемый пост)
память должна по идее выделяется при создании каждого нового объекта , а в твоем варианте при копировании объектов получалось, что 2 объекта владеют одной и тойже памятью 

А деструктор не нужно править? У меня проблемы возникают когда pop делаю из очереди.  Не находит голову очереди.

korbian, не совсем понимаю... можешь кодом объяснить хоть немного?

Автор: Fazil6 7.6.2007, 15:40
Цитата(webgraf @  7.6.2007,  15:29 Найти цитируемый пост)
А деструктор не нужно править? У меня проблемы возникают когда pop делаю из очереди.  Не находит голову очереди.

все он находит. В твоем коде
Код

q.push(pdata(buf1, 600));

после того как эта строка отработает, локальный объект переданный в параметре разрушается и вызывается деструктор, который делает 
Код

free(buf);

но из-за отсытствия твоего конструктора копии объект сохраненный в очередь ссылается на этуже память. И когда ты делаешь pop , вызывается деструктор этого объекта и вызывается повторно free(buf); но этот buf уже освобожден
Цитата(webgraf @  7.6.2007,  15:29 Найти цитируемый пост)
korbian, не совсем понимаю... можешь кодом объяснить хоть немного?

я же написал тебе конструктор копии раньше. В принципе его хватит чтобы от этой ошибки избавиться, но оператор присваивания тоже надо писать

Автор: webgraf 7.6.2007, 15:57
Fazil6, извини что отнимаю время своей тупостью, но пробую вот-так pop-ать :
Код

#include <stdafx.h>
#include <stdio.h>
#include <conio.h>
#include <queue>

// будем хранить данные в структуре типа:
struct pdata
{
    unsigned char * buf;
    unsigned int size;

    // конструктор

    pdata(unsigned char *b, unsigned int s)
    {
        buf = (unsigned char *)malloc(s);
        memcpy(buf,b,s);
        size = s;
    }

    pdata(const pdata &rhs  )
    {
        buf = (unsigned char *)malloc(rhs.size);
        memcpy(buf,rhs.buf,rhs.size);
        size = rhs.size;
    }
    // деструктор
    ~pdata()
    {
        free(buf);
    }
};



int main(int argc, char* argv[])
{
    unsigned char tr;
    unsigned char * buf1 = (unsigned char *)malloc(1000);

    std::queue <pdata> q;
    

    memset(buf1,120,600);     // тестовые данные
    q.push(pdata(buf1, 600));

    memset(buf1,110,600);     // тестовые данные
    q.push(pdata(buf1, 600));

    memset(buf1,100,600);      // тестовые данные
    q.push(pdata(buf1, 600));
    
    if(q.size()>0)
    {
        pdata &info = q.front();
        tr = *(unsigned char *)info.buf;
        printf("%d size=%d\n",tr,q.size());
        q.pop();
    }

    while(!_kbhit());
    return 0;
}

И получаю как раз результат - второй раз front не находит голову. Это как раз из-за оператора присваивания? 

Автор: korbian 8.6.2007, 08:48
Код

pdata& operator=(const pdata &rhs)
{
  if(this != &rhs)
  {
     if(buf != 0)
     {
         free(buf);
     }
      buf = (unsigned char *)malloc(rhs.size);
      memcpy(buf,rhs.buf,rhs.size);
      size = rhs.size;
  }
  return *this;
}

pdata(const pdata &rhs)
 :buf(0), size(0)
{
  this->operator=(rhs);
}

Автор: webgraf 8.6.2007, 11:31
Код

pdata(const pdata &rhs)
 уже прописан в конструкторе
если убрать из конструктора, все равно не присваивает ((
вот что получается:
Код

#include <stdafx.h>
#include <stdio.h>
#include <conio.h>
#include <queue>

// будем хранить данные в структуре типа:
struct pdata
{
    unsigned char * buf;
    unsigned int size;

    // конструктор

    pdata(unsigned char *b, unsigned int s)
    {
        buf = (unsigned char *)malloc(s);
        memcpy(buf,b,s);
        size = s;
    }

    //pdata(const pdata &rhs  )
    //{
    //    buf = (unsigned char *)malloc(rhs.size);
    //    memcpy(buf,rhs.buf,rhs.size);
    //    size = rhs.size;
    //}
    //
    
    // деструктор
    ~pdata()
    {
        free(buf);
    }

    pdata& operator=(const pdata &rhs)
    {
      if(this != &rhs)
      {
         if(buf != 0)
         {
             free(buf);
         }
          buf = (unsigned char *)malloc(rhs.size);
          memcpy(buf,rhs.buf,rhs.size);
          size = rhs.size;
      }
      return *this;
    }

    pdata(const pdata &rhs)
     :buf(0), size(0)
    {
      this->operator=(rhs);
    }
};



int main(int argc, char* argv[])
{
    unsigned char tr;
    unsigned char * buf1 = (unsigned char *)malloc(1000);

    std::queue <pdata> q;
    

    memset(buf1,120,600);
    q.push(pdata(buf1, 600));

    memset(buf1,110,600);
    q.push(pdata(buf1, 600));

    memset(buf1,100,600);
    q.push(pdata(buf1, 600));
    
    pdata &info = q.front();

    if(q.size()>0)
    {
        info = q.front();                    // присваивание
        tr = *(unsigned char *)info.buf;
        printf("%d size=%d\n",tr,q.size());
        q.pop();
    }

    while(!_kbhit());
    return 0;
}

Автор: Fazil6 8.6.2007, 11:49
Цитата(webgraf @  8.6.2007,  11:31 Найти цитируемый пост)
 info = q.front();                    // присваивание

нету здесь присваивания... info у тебя не объект, а ссылка

Добавлено через 3 минуты и 26 секунд
точнее здесь уже есть присваивание, но самому себе

Добавлено через 9 минут и 47 секунд
вообще так работая ты получишь конечно эксепшен. 

Код

pdata &info = q.front();   // инициализируешь ссылку объектом

.....

q.pop(); // удаляешь объект которым инициализирована ссылка
// если теперь сделать так
info = q.front(); // то получишь чпок, потому что ссылка невалидная, а для ее объекта вызывается оператор =

Автор: webgraf 8.6.2007, 12:33
Но если каждый раз инициализировать ссылку, тоже ничего не получается:
Код

    if(q.size()>0)
    {
        pdata &info = q.front();      
        tr = *(unsigned char *)info.buf;
        printf("%d size=%d\n",tr,q.size());
        q.pop();
    }

Автор: Fazil6 8.6.2007, 12:43
Цитата(webgraf @  8.6.2007,  12:33 Найти цитируемый пост)
Но если каждый раз инициализировать ссылку, тоже ничего не получается

что не получается?
То что у тебя написано должно работать нормально. После pop ссылку info использовать нельзя. Откажись от сылки
Код

pdata info = q.front();  // так будет копироваться   


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

while(q.size())
    {
        pdata &info = q.front();                    
        tr = *(unsigned char *)info.buf;
        printf("%d size=%d\n",tr,q.size());
        q.pop();        
    }


Автор: _stranger_ 8.6.2007, 13:07
необходимо добавить цикл while как это правильно показал Fazil6  smile


Автор: webgraf 8.6.2007, 13:30
точно. застрелиться пора.  smile 

огромное спасибо всем.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)