2010-04-08 2 views
1

Я пытаюсь реализовать полиморфную очередь. Вот моя проба:Полиморфная очередь

QQueue <Request *> requests; 

while(...) 
    { 
     QString line = QString::fromUtf8(client->readLine()).trimmed(); 

     if(...)){      
      Request *request=new Request(); 
      request->tcpMessage=line.toUtf8(); 
      request->decodeFromTcpMessage(); //this initialize variables in request using tcpMessage 
      if(request->requestType==REQUEST_LOGIN){ 
       LoginRequest loginRequest; 
       request=&loginRequest; 
       request->tcpMessage=line.toUtf8(); 
       request->decodeFromTcpMessage(); 
       requests.enqueue(request); 
      } 
      //Here pointers in "requests" do not point to objects I created above, and I noticed that their destructors are also called. 
      LoginRequest *loginRequest2=dynamic_cast<LoginRequest *>(requests.dequeue()); 
      loginRequest2->decodeFromTcpMessage(); 
     } 
    } 

К сожалению, мне не удалось сделать работу полиморфного Queue с этим кодом по причине, я упоминал во втором comment.I догадке, мне нужно использовать смарт-указатели, но как ? Я открыт для любого улучшения моего кода или новой реализации полиморфной очереди.

Спасибо.

+0

Это неправильно во многих отношениях, я даже не знаю с чего начать. Для начала: Почему вы сначала конвертируете ввод из UTF-8, а затем обратно в UTF-8? Почему не 'decodeFromTcpMessage()' бесплатная функция принимает строку и возвращает динамически выделенный запрос? Вы помещаете в очередь адрес _local автоматического объекта_ в очередь. (Ouch!) Вы всегда пытаетесь получить «LoginRequest», хотя вы также помещаете других в очередь. Вы получаете доступ к результату 'dynamic_cast', не проверяя, удалось ли отбрасывать. (Почему вы все равно кастовали? Что не так с виртуальными функциями?) ... – sbi

+0

... У меня закончилось свободное пространство, так как комментарий допускает только 600 символов. Я предлагаю вам получить приличную книгу на C++. Например, см. Здесь: http://stackoverflow.com/questions/388242/. – sbi

ответ

2

Есть 2 проблемы в вашем источнике:

  • вы утверждаете память на Request *request=new Request();, которая получает брошенный поздним request=&loginRequest; присвоения (и больше не является файлом удаляемым)
  • переменной LoginRequest loginRequest; получает разрушается, когда выполнение покидает блок {}, где определен переменный, в результате чего оборванного указателя в request

Я хотел бы предложить, чтобы удалить Request *request=new Request(); линии, а затем в if(...){ блоке назначить конкретный LoginRequest объект по

 
LoginRequest* loginRequest = new LoginRequest(); 
/* fill the request */ 
requests.enqueue(loginRequest); 

Вы можете избавиться от очереди объектов путем удаления их вручную, когда они получили poped из очереди (после того, как они обрабатываются), или используя контейнер-безопасный смарт-указатель в очереди (boost :: shared_ptr в порядке, возможно, QT также имеет один из них: std :: auto_ptr НЕ БЕЗОПАСНО БЕЗОПАСНО).

ловушка Также убедитесь, что деструктор запроса является виртуальным, так как вы не можете удалить объекты с помощью указателя базового Классе, когда нет виртуального деструктора в базовом классе (с ++ может вызвать деструктор базового класса с производный экземпляр класса в этом случае, приводящий к неопределенному поведению, например утечка памяти или сбоев)

1

Сразу же из фрагмента кода я вижу, что объект запроса поставлен в очередь, а затем вы пытаетесь его перетащить в LoginRequest. dynamic_cast по праву терпит неудачу. Вам необходимо проанализировать данные запроса и создать объекты соответствующего класса, полученные из запроса. Я бы предложил использовать Factory Pattern для этого.

2

Вы помещаете недействительный указатель на свой QQueue. Если ваш QQueue содержит указатели, вам нужно создать каждый объект, который вы вставляете в него в кучу, то есть с вызовом new. Кроме того, не забудьте освободить первый созданный Request, если он вам не нужен.

Я думаю, вы должны переписать код:

... 
if(request->requestType==REQUEST_LOGIN){ 
    delete request; 
    request = new LoginRequest(); 
    request->tcpMessage=line.toUtf8(); 
    ... 
} 

С помощью этого кода, ваш позже dynamic_cast<LoginRequest*> не подведет.

1

Это также хорошее место для использования заводов, ИМО.

if(...)){ 
    Request *request = CreateRequest(message); 
    requests.enqueue(request); 
} 

Request* request = requests.pop(); 
LoginRequest* login_req = dynamic_cast<LoginRequest*>(request); 
if (login_req != NULL) 
    whatever; 

где

Request* CreateRequest(TcpMessage* message) 
{ 
    TcpMessage* message = line.toUtf8(); 
    RequestType type = message->GetRequestType(); 
    Request* req = NULL; 

    switch (type) 
    { 
    case REQUEST_LOGIN: 
     req = new LoginRequest(message); 
     break; 
    etc. 
    } 

    delete message; 
    return req; 
} 

... а потом, естественно, ваши конструкторы делают правильные вещи с сообщением, инициализирует объекты правильно.

Смежные вопросы