[英]How to dynamically store address of a QVector<T> in another QVector<QVector<T>*>?
我正在处理大量数据,例如 100,000 个双精度值,每 100 毫秒左右收集一次。 我必须在任何给定时间在我的软件中存储 25 个甚至更多这些生成的数据。 每次采集的数据长度和采集次数都因当前情况而异。 我不想将我的数据存储为QVector<QVector<double>>
因为QVector
将数据存储在相邻的内存位置,每次添加QVector<double>
到QVector<QVector<double>>
导致整个事物被复制到一个新的给定的位置,导致巨大的滞后(特别是如果已经有 20 个QVector<double>
并且我正在添加第 21 个)。
我的解决方案是将给定的数据存储为QVector<QVector<double>*>
即每次数据采集我只是将地址存储到QVector
以用于当前采集。 但是,我希望它独立地存储在QVector<QVector<double>*>
即只要我不清除指针就可以访问数据。 我无法弄清楚如何做到这一点。 我尝试了多种方法。 假设我声明QVector<QVector<double>*> myVec;
在我的.h文件中,我使用一个函数在每次采集时向其添加新数据(以下函数仅用于测试,这就是我在函数内创建数据的原因):
void MainWindow::addData()
{
myVec << &QVector<double>(0) // Creating a new empty vector and storing it's location
*myVec[0] << 2.7 << 3.4 << 4.5;
}
这不起作用,大多数时候它会抛出异常,有几次它只是显示一些垃圾值。
void MainWindow::addData()
{
QVector<double> tempVec; // Create a temprory vector
tempVec << 2.7 << 3.4 << 4.5;
myVec << &tempVec;
}
当然,这也不起作用,因为tempVec
addData()
退出, tempVec
被销毁。
void MainWindow::addData()
{
QVector<double> tempVec; // Create a temprory vector
tempVec << 2.7 << 3.4 << 4.5;
myVec << &QVector(tempVec);
}
我认为这会起作用,因为我没有存储tempVec
的地址,而是在新的QVector
复制tempVec
并将其地址分配给myVec
,但它也会引发异常。
有什么办法可以将QVector
纯粹存储为另一个QVector
指针?
您将地址存储到然后被销毁的对象中。 这意味着您的指针向量包含悬空指针:
void MainWindow::addData()
{
myVec << &QVector<double>(0);
// the temporary vector is destroyed here and myVec contains a
// dangling pointer
*myVec[0] << 2.7 << 3.4 << 4.5;
}
我很惊讶你的编译器甚至接受了这段代码,因为获取临时地址应该是一个编译错误。 命名临时文件允许它编译,但也好不到哪里去,因为您仍然会得到一个悬空指针:
void MainWindow::addData()
{
QVector<double> tempVec(0);
myVec << &tempVec;
*myVec[0] << 2.7 << 3.4 << 4.5;
} // <-- tempVec is destroyed here, so you get a dangling pointer
如果存储指向对象的指针,则需要确保在访问该指针时该对象仍然存在。
解决此问题的一种方法是在存储其地址之前用new
分配每个向量。 但是,当您不再需要指针时,您需要记住将其delete
。 取而代之的是,您可以使用智能指针。 在这种情况下std::unique_ptr
可以完成这项工作,但不幸的是QVector
无法存储不可复制的元素。 所以你需要std::shared_ptr
。 这样,除了myVec
,您不需要将指针存储在其他任何地方:
#include <memory>
QVector<std::shared_ptr<QVector<double>>> myVec;
// ...
void MainWindow::addData()
{
myVec << std::make_shared<QVector<double>>(0);
*myVec[0].get() << 2.7 << 3.4 << 4.5;
}
如果您不是绝对需要QVector
并且可以使用std::vector
代替,我建议您这样做,因为它可以很好地存储std::unique_ptr
元素:
#include <memory>
#include <vector>
std::vector<std::unique_ptr<QVector<double>>> myVec;
// ...
void MainWindow::addData()
{
myVec.push_back(std::make_unique<QVector<double>>(0));
*myVec[0].get() << 2.7 << 3.4 << 4.5;
}
如果您真的需要存储原始指针并且不能使用智能指针,那么恐怕您需要通过使用new
分配它们来自己管理指向对象,然后一旦您完成myVec
并且不再需要它,用delete
清理:
QVector<QVector<double>*> myVec;
// ...
void MainWindow::addData()
{
myVec << new QVector<double>(0);
*myVec[0] << 2.7 << 3.4 << 4.5;
}
// Cleanup code you need to call when you no longer need myVec
for (auto ptr : myVec) {
delete ptr;
}
请记住,如果您从myVec
删除一个指针或使用不同的指针覆盖它,您还需要删除它。 这是乏味且容易出错的。 当你忘记这样做时,你就会泄漏内存。 所以我建议改为使用unique_ptr
路由,它会自动为你删除指针。
最后,这在您的情况下可能更可取,您可以完全避免使用指针,并通过使用std::move()
将向量转换为右值来将向量移动到myVec
。 不确定QVector
与移动语义的工作情况如何,但std::vector
可以很好地完成这项工作,在这种情况下,您可以将std::vector
用于“内部”和“外部”向量。 作为优化,如果您知道需要存储的双精度数,则可以使用reserve()
进行预分配,以避免在添加元素时进行代价高昂的重新分配:
#include <memory>
#include <vector>
std::vector<std::vector<double>> myVec;
// ...
void MainWindow::addData()
{
std::vector<double> tmpVec;
tmpVec.reserve(amount_of_elements);
tmpVec.push_back(2.4);
tmpVec.push_back(3.7);
// etc until filled
myVec.push_back(std::move(tmpVec));
}
移动时,如果所涉及的对象支持移动语义,则不执行分配或复制。 如前所述, std::vector
确实如此。
非常重要:在对象被“移出”后(在本例中为tmpVec
),它处于有效但未指定的状态(通常为空)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.