首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在调用QXYSeries::QVector ()之后,当size()没有超过容量()时,为什么会改变这个地址呢?

在调用QXYSeries::QVector ()之后,当size()没有超过容量()时,为什么会改变这个地址呢?
EN

Stack Overflow用户
提问于 2019-09-14 00:31:10
回答 1查看 311关注 0票数 2

我有一个小测试程序,可以将值插入到QVector中。QVector在开始时被保留,以便分配最小的内存量。我验证了容量是正确的,并且QVector的大小没有超过容量。

我注意到,将数据附加到QVector并不会更改第一个元素的地址。到目前为止一切都很好。

然后,我使用QSplineSeries类的替换()方法将数据从向量复制到图表。在调用此方法后,我再次检查QVector中第一个元素的地址,令我感到惊讶的是,地址已经更改了!

在每次调用该方法时都会发生这种情况,我想了解为什么会发生这种情况。我怀疑可能与Qt容器的隐式共享有关,但我不明白为什么要更改这个容器的地址。

示例代码和输出如下所示。

代码语言:javascript
复制
#include <QApplication>
#include <QDebug>
#include <QtCharts/QChart>
#include <QtCharts/QChartView>
#include <QtCharts/QSplineSeries>
#include <memory>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    auto chart = std::make_unique<QtCharts::QChartView>(new QtCharts::QChart());
    chart->chart()->addSeries(new QtCharts::QSplineSeries);

    QVector<QPointF> vector;
    vector.reserve(1000);

    while (true) {
        vector.append(QPointF(0, 0));
        qDebug() << "1. Size: " << vector.size() << " Capacity: " << vector.capacity();
        qDebug() << "1. Address of first element: " << &vector[0];
        auto series = dynamic_cast<QtCharts::QSplineSeries*>(chart->chart()->series().at(0));
        series->replace(vector);
        qDebug() << "2. Size: " << vector.size() << " Capacity: " << vector.capacity();
        qDebug() << "2. Address of first element: " << &vector[0];
    }

    return a.exec();
}

输出

  1. 大小:1容量:1 000
  2. 第一个元素的地址: 0x222725d61e8
  3. 大小:1容量:1 000
  4. 第一个元素的地址: 0x222725dc0d8
  5. 大小:2个容量: 1000
  6. 第一个元素的地址: 0x222725dc0d8
  7. 大小:2个容量: 1000
  8. 第一个元素的地址: 0x222725d61e8
  9. 大小:3个容量: 1000
  10. 第一个元素的地址: 0x222725d61e8
  11. 大小:3个容量: 1000
  12. 第一个元素的地址: 0x222725dc0d8
  13. 大小:4容量: 1000
  14. 第一个元素的地址: 0x222725dc0d8
  15. 大小:4容量: 1000
  16. 第一个元素的地址: 0x222725d61e8
  17. 大小:5容量: 1000
  18. 第一个元素的地址: 0x222725d61e8
  19. 大小:5容量: 1000
  20. 第一个元素的地址: 0x222725dc0d8

链接到QSplineSeries::QVector(此处)调用的源代码

编辑

我刚刚意识到,在QSplineSeries::QVector中调用了的赋值运算符,它看起来像。这意味着QSplineSeries中的内部向量复制我传入的QVector,但我仍然不明白为什么传入的QVector更改它的地址。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-09-14 02:54:15

您已经遇到了Qt容器与标准库容器不同的一种方式。具体来说,Qt使用的是隐式共享和在写上复制。这意味着当容器的副本被复制时,副本和原始数据都指向相同的数据。只有在试图更改其中一个容器的内容时,才会进行深度复制。(被更改的容器获取其数据的新地址,即使它是原始容器。)

让我们将此应用于您的示例。首先,您将获得QVector的统计数据。接下来你叫QSplineSeries::replace(QVector<QPointF>)。此函数的目的是将提供的QVector复制到QSplineSeries的数据中。此副本将保留该函数的返回。(该参数还创建了向量的副本--它不是通过引用传递的--但是该副本在函数返回时被销毁。)因此,当您进入下一行时,vector将与另一个容器共享数据,特别是chart内部的容器。到现在为止还好。

检查vector的大小和容量仍然很好。但是,您使用operator[]。这将返回对向量元素的非常量引用。这意味着你可以写信给它。不管你是否真的写信给它。对象无法知道您将如何处理引用,因此它必须为潜在的写入做好准备。由于数据是共享的,因此将触发深度副本。vector中的数据被复制到一个新的内存块中,您可以在不影响chart的情况下覆盖它。因此,内存地址会发生变化。

如果您想在不触发深度复制的情况下完成分析,请将&vector[0]更改为&vector.at(0)vector.constData()。它们提供了对数据的const-qualified访问,因此不会触发深度复制。

注意:由operator[]使用的const QVector版本返回一个常量引用,因此不会触发深度副本。const的非__ vector性质是这里的一个因素。

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

https://stackoverflow.com/questions/57931574

复制
相关文章

相似问题

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