0

我有一个抽象类,IPacket。

/*
 * Represents an abstract network packet.
 */
class IPacket
{

public:

    virtual void read(...) = 0;

    virtual void write(...) = 0;

    virtual int getID() const = 0;
};

而且我想(并且一直)返回一个像这样的指针:

class PacketMedium
{
    /*!
     * Returns a pointer to the next pending packet or NULL if there are no packets pending.
     * \note The object must deleted when you are finished with it.
     */
    IPacket* receivePacket();
};

现在显然,这是不好的做法;要求调用者删除一个甚至不是自己分配的指针。我相信的约定是使用智能指针,即

class PacketMedium
{
public:

    std::unique_ptr<IPacket*> receivePacket();
};

但由于这是库代码,因此智能指针是一个 nono,尽管我宁愿避免使用它们。

我最好的选择是什么?

谢谢你的帮助 :)

编辑:之前有人问过这个问题,并且给出了很好的答案,尽管它们都建议使用智能指针,或者只是不在堆上分配。鉴于这IPacket是抽象的,堆栈分配将不起作用。

4

3 回答 3

2

一个想法是返回一个参考:

class PacketMedium {
public:
   IPacket &receivePacket();
private:
   IPacketImpl1 impl1;
   IPacketImpl2 impl2;
 };

receivePacket 应按以下方式实现:

IPacket &receivePacket() {
  int data = receiveint();
  if (data==0) { // impl1
      float data = receivefloat();
      impl1.data = data;
      return impl1;
  } else { // impl2
      std::string data = receivestr();
      impl2.str = data;
      return impl2;
  }
}

请注意,使用参考时会有一些基本规则:

  1. 调用 receivePacket() 两次是危险的。第二次调用它可能会删除现有数据。
  2. 您收到的数据应立即使用。长时间存放 IPacets 是危险的。

要解决这些问题,您可以对 IPacket 接口实现新功能:

virtual IPacket *clone() const=0;
于 2013-07-06T09:43:20.463 回答
0

您甚至不需要返回参考。您可以只将公共/相关IPacket接口包装在一个类后面,该类也具有高级操作并在传入数据包被消耗时负责删除它们(即您的类型调用receivePacket())。

如果二进制兼容性是您主要关心的问题,您可以编写自己的简单 unique_ptr。

于 2013-07-06T10:06:35.360 回答
0

另一种解决方案是“句柄”。而不是unique_ptr<IPacket> reveivePacket()你可以将 unique_ptr 包装成这样的类型:

struct IPacketHandle { int id; };
IPacketHandle receivePacket();

但是,数据包存储在哪里?它会在 inside std::vector<IPacket*> vec,但它在您的代码内部。然后做vec.push_back(new IPacketImpl1); handle.id = vec.size()-1;。请注意,从向量中删除项目可能更复杂/应该用 NULL 指针替换对象。

但是等等,现在你失去了 IPacket 接口的读/写功能。需要再次添加它们:

void read_packet(IPacketHandle h, ...) { vec[h.id]->read(...); }
void write_packet(IPacketHandle h, ...) { vec[h.id]->write(...); }

(我已经在一个库中成功使用了这个解决方案,它提供了类似于 haskell 的标准库的很好的函数式编程接口,其中根本没有库用户的内存管理)(还需要考虑 std::vector 的位置小心,这样就不需要使用全局变量了)

于 2013-07-06T11:10:54.533 回答