2010-04-08 37 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; 
} 

...然後,當然,你的構造做正確的事與信息,正確初始化的對象。