将read()直接用于C ++ std:vector

时间:2010-05-06 10:36:25

标签: c++ sockets vector buffer

我在一些C ++中为嵌入式系统包装用户空间linux套接字功能(是的,这可能会再次重新发明轮子)。

我想使用向量提供读写实现。

执行写操作非常简单,我可以通过&myvec[0]并避免不必要的复制。我想做同样的事情并直接读到一个向量,而不是读入一个char缓冲区,然后将所有这些复制到一个新创建的向量中。

现在,我知道我想读多少数据,我可以适当分配(vec.reserve())。我也可以阅读&myvec[0],虽然这可能是一个非常糟糕的想法。显然这样做不允许myvec.size返回任何合理的东西。有没有办法做到这一点:

  1. 从安全/ C ++的角度来看,并不完全令人讨厌
  2. 不涉及数据块的两个副本 - 一次从内核到用户空间,一次从C char *样式缓冲区到C ++向量。

4 个答案:

答案 0 :(得分:22)

使用resize()代替reserve()。这将正确设置向量的大小 - 之后,&myvec[0]像往常一样,保证指向一个连续的内存块。

编辑:使用&myvec[0]作为指向底层数组的指针,用于读取和写入是安全的,并保证可以通过C ++标准工作。这就是Herb Sutter has to say

  

那么为什么人们不断询问std :: vector(或std :: array)的元素是否连续存储?最可能的原因是他们想要知道他们是否可以咳嗽指向内部的指针来共享数据,无论是读取还是写入,以及处理C数组的其他代码。这是一个有效的用途,而且足以保证标准。

答案 1 :(得分:1)

假设它是POD结构,请调用resize而不是reserve。如果在填充向量之前确实不希望数据归零,则可以定义一个空的默认构造函数。

它的水平有点低,但是POD结构的构造语义是故意模糊的。如果允许memmove复制构造它们,我不明白为什么套接字读取不应该。

编辑:啊,字节,不是结构。好吧,您可以使用相同的技巧,并使用char和默认构造函数定义一个结构,忽略初始化它...如果我正确地猜测您关心,这就是您想要调用{{}的原因首先是1}}而不是reserve

答案 2 :(得分:1)

如果您希望向量反映读取的数据量,请两次调用resize()。一旦读完之前,给自己留空读入。在读取之后,再次将向量的大小设置为实际读取的字节数。 reserve()并不好,因为调用reserve并不允许您访问为容量分配的内存。

第一个resize()将向量的元素归零,但这不太可能产生很大的性能开销。如果确实如此,你可以尝试Potatoswatter的建议,或者你可以放弃反映读取数据大小的向量大小,而只是resize()一次,然后重新使用它就像你一样在C中分配缓冲区。

性能方面,如果您在用户模式下从套接字读取数据,很可能您可以轻松地处理数据。如果您在千兆位LAN上连接到另一台计算机,或者您的机器经常运行100%CPU或100%内存带宽。如果你最终要阻止read通话,那么一些额外的复制或memsetting也没什么大不了的。

和你一样,我想避免在用户空间中使用额外的副本,但不是出于性能原因,只是因为如果我不这样做,我就不必为它编写代码......

答案 3 :(得分:1)

我只想补充说明,因为答案已经给出了。参数大于当前大小的resize()将向集合添加元素并默认 - 初始化它们。如果您创建

std::vector<unsigned char> v;

然后调整大小

v.resize(someSize);

所有无符号字符都将初始化为0.顺便说一句你可以用构造函数做同样的事情

std::vector<unsigned char> v(someSize);

所以理论上它可能比原始数组慢一点,但如果替代方法是复制数组,那就更好了。

保留仅准备内存,因此如果将新元素添加到集合中,则无需重新分配,但您无法访问该内存。

您必须获取有关写入向量的元素数量的信息。向量对此一无所知。