如何使用集合元素重用向量?

Posted

技术标签:

【中文标题】如何使用集合元素重用向量?【英文标题】:How to re-use vector with set elements? 【发布时间】:2017-01-20 06:44:59 【问题描述】:

所以我正在使用我的程序将我的 Rasperry Pi 相机流式传输到我的计算机,但是。下面列出的向量给我带来了问题。在大约 30 秒的流式传输后,它给了我std::bad_alloc。有没有办法在循环中一遍又一遍地重用这个向量(例如调整大小,清除)? 这是简化的代码:

while(isRunning)

    recv(Connection, received_message, sizeof(received_message), NULL); //receiving the size of image in bytes
    fileSize = atoi(received_message);

    std::vector<char> fileData(fileSize); //<- this vector is giving me problems

    recv(Connection, &fileData[0], CHUNK_SIZE, 0); //Receiving the image

    //The code loops over and over again

【问题讨论】:

@MK.,OP 将指针传递给向量元素(因此,char*),而不是整个向量。 @MK。这不是一个猜测。 std::vector&lt;char&gt; 保证包含char 的连续数组。不过,安全的做法是使用std::vector::data @user4581301:必须注意,只有当数组为空时,data() 更安全(与operator[] 不同,它仍然保证返回一些有效指针);在所有其他情况下,它们保证完全相同。 @MK.: 因为标准是这样说的;另外,因为否则它会破坏许多有用的用例(与 C 的互操作性以及首先通过原始指针访问元素)。 OK,[vector.overview] 声明“一个向量满足所有要求......对于一个连续容器的 bool 以外的元素类型”这引发了一个支持连续容器的连续容器链[iterator.requirements.general] 要求的迭代器“对于整数值 n 和可解引用的迭代器值 a 和 (a + n),*(a + n) 等效于 *(addressof(*a) + n)” 【参考方案1】:

TCP 是一种流协议。它没有消息的概念。在连接的一端写入 10,000 个字节并不意味着所有 10,000 个字节都将到达接收器并立即可用。

因此,recv 可以与现有内容一起使用。它返回当前可用的任何内容,如果没有可用的,recv 将等待数据可用。这意味着如果您要求 10,000 字节,您可能会完全根据网络堆栈、一个 IP 数据包中可以进入的最大数据量以及太多其他变量无法列出来获得 1 字节到 10,000 字节之间的任何位置。

所以

recv(Connection, received_message, sizeof(received_message), NULL);

可能会在收到所有received_message 之前返回。 fileSize 将根据错误的输入计算,很可能是一个非空终止的字符串,并在缓冲区的末尾运行,触发未定义的行为,垃圾输入将垃圾输出。

这个不正确的fileSize 然后用于调整vector 的大小,现在几乎肯定会是错误的大小。如果太小,

recv(Connection, &fileData[0], CHUNK_SIZE, 0);

可能会超出vector 的末尾以获取更多未定义的行为。如果它太大,系统可能无法为vector 分配存储,因为没有足够的连续存储可用。这似乎是 OP 发生的事情。

解决方案:循环所有对recv 的调用,直到到达所需的数据量后再继续。写入备用路径以处理关闭或失败的连接。所有调用都必须读取正确的数据量或

recv(Connection, &fileData[0], CHUNK_SIZE, 0);

可以提前退出下一个

recv(Connection, received_message, sizeof(received_message), NULL);

将图像的一部分读取为received_message,导致fileSize 的每一位都像received_message 没有完全填充一样疯狂。

还可以考虑在recv 上设置超时,以便在您希望终止程序时有机会读取退出标志。否则它可能会永远阻塞永远不会到达的数据。

【讨论】:

【参考方案2】:

您可以像这样轻松地重复使用您的std::vector

std::vector<char> fileData;

while(isRunning)

    ssize_t n = recv(Connection, received_message, sizeof(received_message), 0); //receiving the size of image in bytes
    if (n < 0)
        throw std::runtime_error(std::string("Connection error (getting fileSize)") + strerror(errno));
    assert(n == sizeof(received_message));

    fileSize = atoi(received_message);

    if (fileSize > maxFileSize or fileSize == 0)
        throw std::runtime_error("Invalid fileSize " + std::to_string(fileSize));

    fileData.resize(fileSize);

    size_t received = 0;
    while (received < fileSize)
    
        ssize_t n = recv(Connection, fileData.data() + received, fileSize - received, 0); //Receiving the image
        if (n < 0)
            throw std::runtime_error(std::string("Connection error (getting image)") + strerror(errno));
        received += n;
    
    //The code loops over and over again

几点说明:

处理第一个recv 没有收到sizeof(received_message) 字节的事件(当前受assert 保护) 你应该定义maxFileSize 包括&lt;cassert&gt;&lt;exception&gt;&lt;string&gt; 标头 使用-std=c++11编译

【讨论】:

断言一个完全正常的状态,recv 不返回请求的数据量,是一个非常非常糟糕的主意。 @user4581301 是的,这留给 OP 练习(虽然有一个例子)

以上是关于如何使用集合元素重用向量?的主要内容,如果未能解决你的问题,请参考以下文章

如何像 uitableviewcell 一样重用/回收自定义元素?

如何在 node.js 中重用 mongodb 连接

如何使用 STL 获取结构向量并将其转换为结构元素的向量

C - 如何使用 GCC SSE 向量扩展访问向量的元素

如何在向量数组中插入元素?

如何使用用户定义的谓词查找向量的最大元素