1

我正在编写一个数据包处理器并具有以下类:

class Parser {
  private:
    Packet* curr_pkt;
  public:
    void parsePacket(unsigned char byte) {
      if(byte == SyncPacket::headerVal) {
        SyncPacket pkt;
        curr_pkt = &pkt;
      }
      if(byte == SyncPacket::headerVal) {
        TypeAPacket pkt;
        curr_pkt = &pkt;
      }
    }
};
class Packet {
  public:
    void parseByte(unsigned char byte) {}
};
class SyncPacket : public Packet {
  public:
    static const unsigned char headerVal = 0x0A;
    void parseByte(unsigned char byte) {
      <do sync>
    }
};
class TypeAPacket : public Packet {
  public:
    static const unsigned char headerVal = 0x0B;
    void parseByte(unsigned char byte) {
      <do type A decode>
    }
};

int main() {
  std::vector<unsigned char> chars;
  <stream in characters>

  Parser pktParser;
  for(unsigned char byte: bytes) {
    pktParser.parseByte(byte);
  }
}

这似乎工作正常,实际上是我认为多态性的用途。但我的问题是:我应该担心这里使用的原始指针吗?是否有更推荐的方法通过智能指针来做到这一点?

例如,在这一行中:

      if(byte == SyncPacket::headerVal) {
        SyncPacket pkt;
        curr_pkt = &pkt;
      }

从技术上讲, pkt 在if语句之后超出了范围,因此通常它的生命周期会结束。但是因为 curr_pkt 指向它,所以它继续存在。这是一个潜在的问题,不是吗?

4

2 回答 2

5

从技术上讲, pkt 在 if 语句之后超出了范围,因此通常它的生命周期会结束。

这是正确的,但在技术上没有任何问题。

但是因为 curr_pkt 指向它,所以它继续存在。

这是不正确的,此时对象不再存在,指针被视为dangling,任何取消引用它的尝试都是未定义的行为。

如果你设法完成了这项工作,那么你很幸运。

是否有更推荐的方法通过智能指针来做到这一点?

与其说是“更推荐”的方式,不如说是一种真正有效的方式,是的。

您确实可以使用智能指针来完成您的代码试图表达的内容。(您不需要智能指针即可到达那里,但它确实使它更安全)。

class Parser {
  private:
    std::unique_ptr<Packet> curr_pkt;
  public:
    void parsePacket(unsigned char byte) {
      if(byte == SyncPacket::headerVal) {
        curr_pkt = std::make_unique<SyncPacket>();
      }
      if(byte == SyncPacket::headerVal) {
        curr_pkt = std::make_unique<TypeAPacket>();
      }
    }
};
于 2021-09-14T03:28:03.437 回答
3

Yes this returning the address of a local variable is not going to work. And there is more to polymorphism, as explained in this example

#include <cstdint>
#include <memory>
#include <vector>

//-------------------------------------------------------------------------------------------------
// Packet is going to be an abstract base class 
// (closest thing C++ has to an interface)
class Packet_itf
{
public:
    // Dynamic polymorphism means virtual functions
    // for interfaces this will be pure virtual functions
    virtual void parseByte(unsigned char byte) = 0;

    // destructor needs to be virtual
    virtual ~Packet_itf() = default;

protected:
    // protected constructor Packet_itf is not supposed to be instantiated
    Packet_itf() = default;

    // todo delete copy/move/assignment rule of 5
};

//-------------------------------------------------------------------------------------------------
// define a null strategy for the interface
// an implementation that does nothing

class NullPacket :
    public Packet_itf
{
    void parseByte(unsigned char byte) override
    {
    }
};

//-------------------------------------------------------------------------------------------------
// here are your packets

class SyncPacket :
    public Packet_itf
{
public:
    static const std::uint8_t headerVal = 0x0A;

    void parseByte(unsigned char byte) override
    {
        //<do sync>
    }
};

//-------------------------------------------------------------------------------------------------

class TypeAPacket :
    public Packet_itf
{
public:
    static const std::uint8_t headerVal = 0x0B;

    void parseByte(unsigned char byte) override
    {
        //<do type A decode>
    }
};

//-------------------------------------------------------------------------------------------------
// Dynamic polymorphism renamed parser to factory
// factory pattern

class PacketFactory
{
public:

    static std::unique_ptr<Packet_itf> createPacket(const std::uint8_t byte)
    {
        switch (byte)
        {

        case SyncPacket::headerVal:
        {
            return std::make_unique<SyncPacket>();
        }
        break;

        case TypeAPacket::headerVal:
        {
            return std::make_unique<TypeAPacket>();
        }
        break;

        default:
            // error handling here
            break;
        }

        // return a default packet that does nothing
        // Null strategy pattern
        return std::make_unique<NullPacket>();
    }
};

//-------------------------------------------------------------------------------------------------

int main()
{
    //<stream in characters>
    // note 0x02 isn't know yet so ut will result in a NullPacket
    // no ifs in the loop need to handle that case.

    std::vector<std::uint8_t> bytes{ SyncPacket::headerVal, TypeAPacket::headerVal, 0x02 };


    for (const auto byte : bytes)
    {
        // now packet is a unique ptr that will live for the lifetime
        // of this for loop then it will be deleted.
        auto packet = PacketFactory::createPacket(SyncPacket::headerVal);

        std::vector<std::uint8_t> data{ 0x00,0x00,0x01,0x03 };
        for (const auto value : data)
        {
            packet->parseByte(value);
        }
    }

    return 0;
}
于 2021-09-14T03:41:09.767 回答