2010-04-08 33 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(); 
     } 
    } 

不幸的是,我无法管理,使工作多态性队列与此代码,因为我在第二comment.I猜测提到的原因,我需要使用智能指针,但如何? 我愿意对我的代码或多态队列的新实现进行任何改进。

谢谢。

+0

这在许多方面都是错误的,我甚至不知道从哪里开始。对于初学者:你为什么首先将输入从UTF-8转换回UTF-8?为什么不'decodeFromTcpMessage()'一个自由函数接受一个字符串并返回一个动态分配的请求?你把一个_local自动对象的地址排入队列。 (Ouch!)你总是试图检索一个'LoginRequest',尽管你也将其他人放入队列中。您可以访问'dynamic_cast'的结果而不检查转换是否成功。 (为什么你要继续演出?虚拟功能有什么问题?)... – sbi 2010-04-08 12:28:51

+0

...我用完了空间,因为评论只允许600个字符。我建议你给自己一本体面的C++书。例如,看到这里:http://stackoverflow.com/questions/388242/。 – sbi 2010-04-08 12:32:31

回答

2

有2个问题,在您的源:

  • 您的Request *request=new Request();,它获取由后request=&loginRequest;分配遗弃(而不再是可删除的)
  • LoginRequest loginRequest;变量被破坏时,要求内存执行离开变量定义的块,导致一个悬挂指针 request

我建议删除Request *request=new Request();行,后来在if(...){块由

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

分配具体LoginRequest对象可以摆脱通过手动删除他们,当他们得到了POP操作从队列中(它们被处理后)排队的对象,或者通过在队列中使用容器安全智能指针(boost :: shared_ptr很好,也许QT也有其中之一,std :: auto_ptr不是容器安全的)。

陷阱还要确保请求的析构函数是虚拟的,因为你不能用一个指向它的基础CLASSE删除对象时,有在基类中没有虚析构函数(C++可以调用基类的析构函数与派生类实例在这种情况下,导致未定义的行为,如内存泄漏或崩溃)

1

立即从代码片段中,我可以看到Request的一个对象已排队,后来您尝试将它向下注册到LoginRequest。 dynamic_cast将正确失败。您必须解析请求数据并创建适当类的对象,这些对象源自请求。我会建议使用工厂模式。

2

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

我想你应该重写你的代码:

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

有了这个代码,你以后的dynamic_cast<LoginRequest*>不会失败。

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

...然后,当然,你的构造做正确的事与信息,正确初始化的对象。