【问题标题】: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)”

标签: c++ linux windows vector raspberry-pi


【解决方案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 练习(虽然有一个例子)
    猜你喜欢
    • 2016-08-28
    • 1970-01-01
    • 1970-01-01
    • 2019-05-13
    • 2019-08-23
    • 1970-01-01
    • 2020-05-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多