在不复制的情况下构建范围内的向量



我有一个类,它包装了一大堆字节,这些字节是网络数据包。该类实现一个队列并提供(除其他外)front()函数,该函数返回构成队列中最早数据包的字节的常量向量。

class Buffer{
  unsigned char data[65536];
  unsigned int offset;
  unsigned int length;
  [...]//other fields for maintaining write ptr etc.
public:
  const std::vector<unsigned char> front(){
    return std::vector<unsigned char>(data + offset, data + offset + length);
  }
  //other methods for accessing the queue like
  //pop(), push(), clean() and so forth...
  [...]
}

上述front()函数实现的性能受到当前数据包占用的范围内不必要的复制字节的影响。由于向量是常量,因此无需复制数据。我想要的是在缓冲区中已经存储的数据上创建一个向量。当然,向量的析构函数不应该释放内存。

您有一些选项可供您使用:

  1. 与其返回vector,不如返回一个const char*
const char* front() {
    return data;
}
  1. 请考虑使用标准容器(如 string data)作为Buffer成员。这将允许您执行以下操作:
const string& front() {
    return data;
}
  1. 最好的选择是,如果您有 C++17 或可以访问experimental::string_view您可以这样做:
const string_view front() {
    return string_view(data);
}

只是一个约定注释,front会期望它的行为与其他标准容器一样,它:

返回对容器中第一个元素的引用。
未定义对空容器的调用前端。

[来源]

C++标准委员会还讨论了将前端应用于固定大小的裸数组: 正面和背面 迭代器库提案

因为这种方法更接近于data,它:

返回指向包含容器元素的内存块的指针。

[来源]

如果您希望避免不必要的复制,则需要返回数据的视图。您可以提供一组front_begin()front_end()函数集:

const char *front_begin() const
{
  return data + offset;
}
const char *front_end() const
{
  return data + offset + length;
}

或者编写一个包装类:

class Data
{
private:
  const char *m_Begin;
  const char *m_End;
public:
  Data(const char *begin, const char *end) : m_Begin(begin), m_End(end)
  {
  }
  const char *begin() const
  {
    return m_Begin;
  }
  const char *end() const
  {
    return m_End;
  }
}

并让您的front()方法返回以下之一:

Data front()
{
  return Data(data + offset, data + offset + length)
}

如果您使用的是 C++11,则可以在基于范围 for 循环中使用 Data 实例:

Data data = buffer.front();
for(char c : data)
{
  // Do something with the data
}

最新更新