Полиморфная очередь - PullRequest
       8

Полиморфная очередь

1 голос
/ 08 апреля 2010

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

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();
        }
    }

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

Спасибо.

Ответы [ 4 ]

2 голосов
/ 08 апреля 2010

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

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

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

С этим кодом ваша более поздняя dynamic_cast<LoginRequest*> не подведет.

2 голосов
/ 08 апреля 2010

В вашем источнике 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);

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

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

1 голос
/ 09 апреля 2010

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

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;
}

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

1 голос
/ 08 апреля 2010

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...