C++中的动态缓冲区类型?

Vil*_*lx- 25 c++ buffer memory-management stl dynamic

我不是一个C++新手,但我过去几乎没有认真对待它,所以我对它的设施的了解相当粗略.

我正在用C++编写一个快速概念验证程序,我需要一个动态大小的二进制数据缓冲区.也就是说,我将从网络套接字接收数据,我不知道会有多少(虽然不超过几MB).我自己可以编写这样的缓冲区,但是为什么标准库可能已经有了什么呢?我正在使用VS2008,因此我可以使用一些特定于Microsoft的扩展.我只需要四个操作:

  • 创建缓冲区
  • 将数据写入缓冲区(二进制垃圾,而不是零终止)
  • 将写入的数据作为char数组(及其长度)获取
  • 释放缓冲区

类/函数集的名称是什么/我需要什么?

补充:几票投票std::vector.一切都很好,但我不想逐字节地推送几MB的数据.套接字将以几KB大块的形式向我提供数据,所以我想一次性写入它们.另外,最后我需要将数据作为一个简单的char*,因为我需要将整个blob传递给一些未经修改的Win32 API函数.

GMa*_*ckG 39

你想要一个std::vector:

std::vector<char> myData;
Run Code Online (Sandbox Code Playgroud)

vector将自动为您分配和释放其内存.使用push_back添加新数据(vector将如果需要你调整),以及索引操作符[]来获取数据.

如果在任何时候你可以猜出你需要多少内存,我建议你调用reserve以便后续push_back的内存不必再重新分配.

如果你想读入一大块内存并将其附加到缓冲区,最简单的可能是:

std::vector<char> myData;
for (;;) {
    const int BufferSize = 1024;
    char rawBuffer[BufferSize];

    const unsigned bytesRead = get_network_data(rawBuffer, sizeof(rawBuffer));
    if (bytesRead <= 0) {
        break;
    }

    myData.insert(myData.end(), rawBuffer, rawBuffer + bytesRead);
}
Run Code Online (Sandbox Code Playgroud)

myData现在拥有所有读取数据,按块读取块.但是,我们要复制两次.

我们改为尝试这样的事情:

std::vector<char> myData;
for (;;) {
    const int BufferSize = 1024;

    const size_t oldSize = myData.size();
    myData.resize(myData.size() + BufferSize);        

    const unsigned bytesRead = get_network_data(&myData[oldSize], BufferSize);
    myData.resize(oldSize + bytesRead);

    if (bytesRead == 0) {
        break;
    }
}
Run Code Online (Sandbox Code Playgroud)

它直接读入缓冲区,但代价是偶尔会过度分配.

这可以通过例如将每个调整大小的矢量大小加倍来分摊调整大小来变得更聪明,因为第一个解决方案是隐式的.当然,reserve()如果您具有最终缓冲区的可能大小的先验知识,则可以预先设置更大的缓冲区,以最小化调整大小.

两者都留给读者练习.:)

最后,如果您需要将数据视为原始数组:

some_c_function(myData.data(), myData.size());
Run Code Online (Sandbox Code Playgroud)

std::vector 保证是连续的.

  • 为何使用中间缓冲区?为什么不直接将网络数据读入矢量?将向量的大小调整为其旧大小+ N,将最大N个字节接收到&vector [old_vector_size]. (4认同)
  • 向量必须是连续的,因此可以将元素的地址和memcopy()一个数据块放入其中.对此恐怖感到不寒而栗. (3认同)

Nik*_*nić 9

std::vector<unsigned char> buffer;
Run Code Online (Sandbox Code Playgroud)

每个push_back都会在最后添加新的char(如果需要,可以重新分配).如果您大致知道预期的数据量,可以调用reserve来最小化分配数量.

buffer.reserve(1000000);
Run Code Online (Sandbox Code Playgroud)

如果您有这样的事情:

unsigned char buffer[1000];
std::vector<unsigned char> vec(buffer, buffer + 1000);
Run Code Online (Sandbox Code Playgroud)


Wyz*_*a-- 7

std::string 会为此工作:

  • 它支持嵌入的空值.
  • 您可以通过append()使用指针和长度调用它来向其附加多字节数据块.
  • 您可以通过调用data()它来将其内容作为char数组获取,并通过调用size()length()在其上获取当前长度.
  • 释放缓冲区由析构函数自动处理,但您也可以调用clear()它来擦除其内容而不会破坏它.

  • 是的,当我说它支持嵌入式空值时,这就是我的意思. (3认同)

sbk*_*sbk 6

再为std :: vector投票.最小的代码,跳过额外的副本GMan的代码:

std::vector<char> buffer;
static const size_t MaxBytesPerRecv = 1024;
size_t bytesRead;
do
{
    const size_t oldSize = buffer.size();

    buffer.resize(oldSize + MaxBytesPerRecv);
    bytesRead = receive(&buffer[oldSize], MaxBytesPerRecv); // pseudo, as is the case with winsock recv() functions, they get a buffer and maximum bytes to write to the buffer

    myData.resize(oldSize + bytesRead); // shrink the vector, this is practically no-op - it only modifies the internal size, no data is moved/freed
} while (bytesRead > 0);
Run Code Online (Sandbox Code Playgroud)

至于调用WinAPI函数 - 使用&buffer [0](是的,它有点笨拙,但这就是它的方式)传递给char*参数,buffer.size()作为长度.

最后一点,您可以使用std :: string而不是std :: vector,应该没有任何区别(除非您可以编写buffer.data()而不是&buffer [0],如果缓冲区是一个字符串)