首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何将QVector<T>的地址动态地存储在另一个QVector<QVector<T>*>中?

如何将QVector<T>的地址动态地存储在另一个QVector<QVector<T>*>中?
EN

Stack Overflow用户
提问于 2020-10-04 14:20:35
回答 1查看 123关注 0票数 1

我正在处理大量的数据,大约100,000个双值,每100毫秒左右收集一次。我必须在任何时候在我的软件中存储这些生成的数据中的25个甚至更多。两种情况下,每次收购的数据长度以及收购次数都因当前情况而异。我不想将我的数据存储为QVector<QVector<double>>,因为QVector将数据存储在相邻的内存位置,而QVector<double>QVector<QVector<double>>的每次添加都会导致整个事物被复制到给定的新位置,从而造成巨大的滞后(特别是如果已经有20 QVector<double>,并且我要在其中添加第21QVector<double>)。

我的解决方案是将给定的数据存储为QVector<QVector<double>*>,也就是说,我只是将当前获取的地址存储到QVector。但是,我希望它独立地存储在QVector<QVector<double>*>中,也就是说,只要我不清除指针,我就能够访问数据。我想不出该怎么做。我尝试过多种方法。假设我在我的.h文件中声明了.h,并使用一个函数在每次获取时向它添加新的数据,如下所示(下面的函数只是用于测试,这就是为什么我要在函数中创建数据):

代码语言:javascript
复制
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;
}

这不起作用,大多数情况下它会抛出一个异常,并且有几次它只显示一些垃圾值。

代码语言:javascript
复制
void MainWindow::addData()
{
    QVector<double> tempVec; // Create a temprory vector
    tempVec << 2.7 << 3.4 << 4.5;
    myVec << &tempVec;
}

当然,这也不起作用,因为一旦tempVec退出addData()addData()就会被销毁。

代码语言:javascript
复制
void MainWindow::addData()
{
    QVector<double> tempVec; // Create a temprory vector
    tempVec << 2.7 << 3.4 << 4.5;
    myVec << &QVector(tempVec);
}

我认为这样做是可行的,因为我不是存储tempVec的地址,而是将tempVec复制到新的QVector中并将其地址分配给myVec,但它也会引发异常。

是否有任何方法可以将QVector 纯粹作为指针存储在另一个QVector中?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-10-04 14:49:19

您正在存储对象的地址,然后这些对象被销毁。这意味着您的指针向量包含悬空指针:

代码语言:javascript
复制
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;
}

我很惊讶您的编译器竟然接受这段代码,因为获取临时地址应该是编译错误。临时命名允许编译,但也没有什么更好的,因为仍然有一个悬空指针:

代码语言:javascript
复制
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

代码语言:javascript
复制
#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元素:

代码语言:javascript
复制
#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进行清理。

代码语言:javascript
复制
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路由,它将自动为您删除指针。

最后,在您的情况下,这可能更好,您可以完全避免指针,并通过使用将向量转换为rvalue,从而将移动到myVec中。不确定QVector如何处理移动语义,但std::vector做得很好,在这种情况下,您将对“内部”和“外部”向量使用std::vector。作为一种优化,如果您知道需要存储的加倍量,可以使用reserve()预分配,以避免在添加元素时重新分配的代价高昂:

代码语言:javascript
复制
#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)之后,它处于有效但未指定的状态(通常为空)。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/64195788

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档