多态队列

发布于 2024-08-28 02:22:57 字数 1136 浏览 6 评论 0原文

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

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

不幸的是,由于我在第二条评论中提到的原因,我无法使用此代码来使多态队列工作。我想,我需要使用智能指针,但是如何呢? 我愿意接受我的代码的任何改进或多态队列的新实现。

谢谢。

I'm trying to implement a Polymorphic Queue.
Here is my trial:

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

Unfortunately, I could not manage to make work Polymorphic Queue with this code because of the reason I mentioned in second comment.I guess, I need to use smart-pointers, but how?
I'm open to any improvement of my code or a new implementation of polymorphic queue.

Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

森末i 2024-09-04 02:22:57

您的源代码中有两个问题:

  • 您通过 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);

您可以通过在队列中的对象弹出时(处理后)手动删除它们来删除它们,或者使用容器安全的智能指针< /strong> 在队列中(boost::shared_ptr 没问题,也许 QT 也有其中之一,std::auto_ptr 不是容器安全的)。

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

There are 2 problems in your source:

  • you claim memory by the Request *request=new Request();, which gets abandoned by the later request=&loginRequest; assignment (and is no longer deletable)
  • the LoginRequest loginRequest; variable gets destructed when the execution leaves the {} block where the variable is defined, resulting in a dangling pointer in
    request

I would suggest to remove the Request *request=new Request(); line, and later in the if(...){ block assign the concrete LoginRequest object by

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

You can get rid of the queued objects by deleting them manually when they got poped out of the queue (after they are processed), or by using a container-safe smartpointer in the queue (boost::shared_ptr is fine, maybe QT has also one of them, std::auto_ptr IS NOT container-safe).

PITFALL Also make sure that the destructor of Request is virtual, since you cannot delete objects by a pointer to its base classe when there is no virtual destructor in the base class(c++ can call the base class destructor with the derived class instance in this case, leading in undefined behavior like memory leaks or crashes)

帝王念 2024-09-04 02:22:57

您将无效的指针放入QQueue。如果您的QQueue 保存指针,您需要在堆上创建插入其中的每个对象,即通过调用new。另外,如果不需要,请不要忘记释放第一个创建的Request

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

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

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

You are putting invalid pointer to your QQueue. If your QQueue holds pointers, you need to create every object you insert to it on the heap, i.e. with a call to new. Also, do not forget to free the first created Request if you do not need it.

I think you should rewrite your code to:

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

With this code, your later dynamic_cast<LoginRequest*> will not fail.

寄与心 2024-09-04 02:22:57

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

Immediately from the code snippet I can see that an object of Request is queued and later you try to downcast it to LoginRequest. dynamic_cast will rightfully fail. You have to parse request data and create objects of appropriate class, derived from Request. I would suggest using Factory Pattern for this.

最美的太阳 2024-09-04 02:22:57

在我看来,这也是一个使用工厂的好地方。

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

...然后,自然地,您的构造函数会对该消息执行正确的操作,正确初始化对象。

This is also a good place to use factories, 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;

where

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

...and then, naturally, your constructors do the right thing with the message, initializing the objects properly.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文