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

残念ながら、2番目のコメントで述べた理由により、このコードでPolymorphic Queueを機能させることができませんでした。おそらく、スマートポインターを使用する必要がありますが、どうすればよいでしょうか。私は自分のコードの改善やポリモーフィックキューの新しい実装を受け入れています。

ありがとう。

4

4 に答える 4

2

に無効なポインタを置いていますQQueue。がポインタを保持している場合QQueueは、ヒープ上に挿入するすべてのオブジェクトを作成する必要があります。つまり、を呼び出しますnewRequestまた、必要がない場合は、最初に作成したものを解放することを忘れないでください。

コードを次のように書き直す必要があると思います。

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

このコードを使用すると、後でdynamic_cast<LoginRequest*>失敗することはありません。

于 2010-04-08T09:55:24.977 に答える
2

ソースには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もそれらの1つ、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 に答える