2

我正在尝试实现多态队列。这是我的试验:

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

4 回答 4

2

您正在将无效指针指向您的QQueue. 如果您QQueue持有指针,则需要在堆上创建插入到它的每个对象,即调用new. 另外,如果不需要,不要忘记释放第一个创建的Request

我认为您应该将代码重写为:

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

使用此代码,您的以后dynamic_cast<LoginRequest*>将不会失败。

于 2010-04-08T09:55:24.977 回答
2

您的来源中有两个问题:

  • 您通过 声明内存,该内存被Request *request=new Request();后来的request=&loginRequest;分配放弃(并且不再可删除)
  • 当执行离开定义变量的 {} 块时,LoginRequest loginRequest;变量会被破坏,从而导致指针悬空 request

我建议删除该Request *request=new Request();行,然后在if(...){块中分配具体LoginRequest对象

LoginRequest* loginRequest = new LoginRequest();
/* 填写请求 */
requests.enqueue(loginRequest);

您可以通过在它们从队列中弹出时手动删除它们(在它们被处理之后)或通过在队列中使用容器安全的智能指针来摆脱排队的对象(boost::shared_ptr 很好,也许 QT 也有其中之一,std::auto_ptr 不是容器安全的)。

PITFALL还要确保Request的析构函数是虚拟的,因为当基类中没有虚拟析构函数时,您不能通过指向其基类的指针来删除对象(在这种情况下,c ++可以使用派生类实例调用基类析构函数,导致未定义的行为,如内存泄漏或崩溃)

于 2010-04-08T10:04:40.213 回答
1

从代码片段中我可以立即看到 Request 的对象已排队,稍后您尝试将其向下转换为 LoginRequest。dynamic_cast 将理所当然地失败。您必须解析请求数据并创建从请求派生的适当类的对象。我建议为此使用工厂模式。

于 2010-04-08T09:34:18.417 回答
1

这也是使用工厂的好地方,IMO。

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

...然后,自然地,您的构造函数对消息做正确的事情,正确初始化对象。

于 2010-04-09T01:51:49.557 回答