如何使用集合元素重用向量?
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<char>
保证包含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
包括<cassert>
、<exception>
和<string>
标头
使用-std=c++11
编译
【讨论】:
断言一个完全正常的状态,recv
不返回请求的数据量,是一个非常非常糟糕的主意。
@user4581301 是的,这留给 OP 练习(虽然有一个例子)以上是关于如何使用集合元素重用向量?的主要内容,如果未能解决你的问题,请参考以下文章