构造范围内的向量而不复制

时间:2016-04-25 11:15:38

标签: c++ vector stdvector allocator placement-new

我有一个包含大量字节的类,这些字节是网络数据包。该类实现一个队列并提供(以及其他)front()函数,该函数返回构成队列中最旧数据包的字节的const向量。

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

2 个答案:

答案 0 :(得分:1)

您可以选择一些选项:

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

        只是一个约定评论,期望front它会像其他标准容器一样表现,其中:

          

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

        [source]

        C ++标准委员会还讨论了在固定大小的阵列上应用裸露的前端:front and back Proposal for iterators Library

        因为这种方法更像data,所以:

          

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

        [source]

答案 1 :(得分:0)

如果您希望避免不必要的复制,那么您需要将视图返回到数据中。您可以提供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
}