qt初入门0:结构体中QString用memset导致崩溃分析及QLatin1String简单查看源码

初识Qt,进行开发时遇到一个崩溃问题 简单整理

1:问题描述如下,结构体中QString成员,然后对结构体调用了memset导致问题:

在这里插入图片描述

2:问题分析,加断点调试的方式可以明确分析到行数

可以明确看出,初始化时成员变量的值为空的字符串,然后执行memset后,该成员地址无法访问。
在这里插入图片描述

3:找源码进行分析一下

3.1.这里首先测试一下string等其他成员操作,没有出现问题。

3.2 分析QString的源码,了解原因(qtbase源码分析)。

简化后源码如下

const QArrayData QArrayData::shared_null[2] = {{ -1, 0, 0, 0, sizeof(QArrayData) }, }
inline QString::QString() noexcept : d(Data::sharedNull()) {}
inline QString::~QString() { if (!d->ref.deref()) Data::deallocate(d); }class Q_CORE_EXPORT QString
{
public:typedef QStringData Data; //基类是 QArrayDatainline QString() noexcept;
private:Data *d; //基类是 QArrayData 控制引用计数
public:typedef Data * DataPtr;inline DataPtr &data_ptr() { return d; }
};QString::QString(const QChar *unicode, int size)
{if (!unicode) {d = Data::sharedNull();} else {if (size < 0) {size = 0;while (!unicode[size].isNull())++size;}if (!size) {d = Data::allocate(0);} else {d = Data::allocate(size + 1);Q_CHECK_PTR(d);d->size = size;memcpy(d->data(), unicode, size * sizeof(QChar));d->data()[size] = '\0';}}
}

第一个分析点(构造函数):
在这里插入图片描述

第二个分析点,真正控制QString的数据体,只能指针+数据域

实际真正的底层是QArrayData

struct Q_CORE_EXPORT QArrayData
{QtPrivate::RefCount ref; //基类实现原子变量的递增递减int size;uint alloc : 31;uint capacityReserved : 1;qptrdiff offset; // in bytes from beginning of headervoid *data() {Q_ASSERT(size == 0  || offset < 0 || size_t(offset) >= sizeof(QArrayData));return reinterpret_cast<char *>(this) + offset;}static const QArrayData shared_null[2];static QArrayData *sharedNull() noexcept { return const_cast<QArrayData*>(shared_null); }
};//真正的申请内存
QArrayData *QArrayData::allocate(size_t objectSize, size_t alignment,size_t capacity, AllocationOptions options) noexcept
{Q_ASSERT(alignment >= Q_ALIGNOF(QArrayData)            && !(alignment & (alignment - 1)));if (!(options & RawData) && !capacity) {return const_cast<QArrayData *>(&qt_array_empty);}size_t headerSize = sizeof(QArrayData);if (!(options & RawData))headerSize += (alignment - Q_ALIGNOF(QArrayData));if (headerSize > size_t(MaxAllocSize))return nullptr;size_t allocSize = calculateBlockSize(capacity, objectSize, headerSize, options);QArrayData *header = static_cast<QArrayData *>(::malloc(allocSize));if (header) {quintptr data = (quintptr(header) + sizeof(QArrayData) + alignment - 1)& ~(alignment - 1);header->ref.atomic.storeRelaxed(1);header->size = 0;header->alloc = capacity;header->capacityReserved = bool(options & CapacityReserved);header->offset = data - quintptr(header);}return header;
}//真正的释放内存 根据引用计数控制
void QArrayData::deallocate(QArrayData *data, size_t objectSize, size_t alignment) noexcept
{// Alignment is a power of twoQ_ASSERT(alignment >= Q_ALIGNOF(QArrayData)  && !(alignment & (alignment - 1)));Q_UNUSED(objectSize) Q_UNUSED(alignment)Q_ASSERT_X(data == 0 || !data->ref.isStatic(), "QArrayData::deallocate","Static data cannot be deleted");::free(data);
}

4:为什么string成员没有问题呢(分析QLatin1String)

这里在看QString源码时看到了QLatin1String类 区分QString进行了简单查看。

首先:QLatin1String作为结构体成员,也没有问题。
在这里插入图片描述

4.1 简单查看QLatin1String的源码

class QLatin1String
{
public:Q_DECL_CONSTEXPR inline QLatin1String() noexcept : m_size(0), m_data(nullptr) {}Q_DECL_CONSTEXPR inline explicit QLatin1String(const char *s) noexcept : m_size(s ? int(strlen(s)) : 0), m_data(s) {}Q_DECL_CONSTEXPR explicit QLatin1String(const char *f, const char *l): QLatin1String(f, int(l - f)) {}Q_DECL_CONSTEXPR inline explicit QLatin1String(const char *s, int sz) noexcept : m_size(sz), m_data(s) {}inline explicit QLatin1String(const QByteArray &s) noexcept : m_size(int(qstrnlen(s.constData(), s.size()))), m_data(s.constData()) {}//。。。其他都是基本的函数接口Q_DECL_CONSTEXPR const char *latin1() const noexcept { return m_data; }Q_DECL_CONSTEXPR int size() const noexcept { return m_size; }Q_DECL_CONSTEXPR const char *data() const noexcept { return m_data; }Q_DECL_CONSTEXPR bool isNull() const noexcept { return !data(); }Q_DECL_CONSTEXPR bool isEmpty() const noexcept { return !size(); }private:int m_size;const char *m_data;
};

4.2 简单分析 QLatin1String 就是对char*的简单封装

在这里插入图片描述

4.2 细节,没看到有operator= 使用赋值构造也没有问题

这是因为用了浅拷贝,内部没涉及内存的重新申请 所以也没问题。

然后因为demo中x1重新赋值,浅拷贝导致x1中data指向的const char*指向发生变化。

总结:QLatin1String只是对char*的简单封装,不涉及内存的申请,实际还是需要我们控制。

遗留:过程中看到QString中相关的编码相关函数,这块也是一个细节,待整理

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/94557.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux:shell函数

目录 一、基本格式 二、查看函数 三、删除函数 四、函数的返回值 五、函数的传参数 六、函数的作用范围 ​七、函数的递归 在编写脚本时&#xff0c;有些脚本可以反复使用&#xff0c;可以调用函数来解决 语句块定义成函数约等于别名 函数使用方法&#xff1a; 定义函…

金蝶软件实现Excel数据复制分录信息粘贴到单据体分录行中

>>>适合KIS云专业版V16.0|KIS云旗舰版V7.0|K/3 WISE 14.0等版本<<< 实现Excel数据复制分录信息粘贴到金蝶单据体分录中,在采购订单|采购入库单|销售订单|销售出库单等类型单据中,以少量的必要字段在excel表格中按模板填列好,很方便快捷地复制到金蝶单据表体…

网络安全威胁与防御策略

第一章&#xff1a;引言 随着数字化时代的快速发展&#xff0c;网络已经成为人们生活和工作中不可或缺的一部分。然而&#xff0c;网络的广泛应用也引发了一系列严峻的网络安全威胁。恶意软件、网络攻击、数据泄露等问题层出不穷&#xff0c;给个人和企业带来了巨大的风险。本文…

JVM - 垃圾回收机制

JVM的垃圾回收机制(简称GC) JVM的垃圾回收机制非常强大&#xff0c;是JVM的一个很重要的功能&#xff0c;而且这也是跟对象实例息息相关的&#xff0c;如果对象实例不用了要怎么清除呢&#xff1f; 如何判断对象已经没用了 当JVM认为一个对像已经没用了&#xff0c;就会把这个…

Airbnb开源数据可视化工具Visx

一、什么是visx visx 是用于 React 的富有表现力的底层可视化组件集合,结合了 d3 的强大功能来生成可视化,以及 React 更新 DOM 的诸多优势。 在 Airbnb 内部,visx 的目标是统一整个公司的可视化堆栈,在此过程中,创建了 visx 项目,从而有效的将 D3 的强大功能与 React …

手写代码-前端面试

GitHub&#xff1a;手写代码集合

一文教你快速 Cloudreve搭建云盘系统,实现随时访问

文章目录 1、前言2、本地网站搭建2.1 环境使用2.2 支持组件选择2.3 网页安装2.4 测试和使用2.5 问题解决 3、本地网页发布3.1 cpolar云端设置3.2 cpolar本地设置 4、公网访问测试5、结语 1、前言 自云存储概念兴起已经有段时间了&#xff0c;各互联网大厂也纷纷加入战局&#…

Redis——list类型详解

概要 Redis中的list类型相当于双端队列&#xff0c;支持头插&#xff0c;头删&#xff0c;尾插&#xff0c;尾删&#xff0c;并且列表中的内容是可以重复的。 如果搭配使用rpush和lpop&#xff0c;那么就相当于队列 如果搭配使用rpush和rpop&#xff0c;那么就相当于栈 lpu…

unity拓展 unity自带的类(Tranform为例)

因为我们使用了ILRuntime热更&#xff0c;unity 打出的WebGL包&#xff0c;运行就会报找不到DoTween里面的方法&#xff0c;所以吧DoTween拓展到tranform类里面&#xff0c;这样就不会报错了&#xff0c;下面是示例 using DG.Tweening; using System.Collections; using Syste…

git环境超详细配置说明

一&#xff0c;简介 在git工具安装完成之后&#xff0c;需要设置一下常用的配置&#xff0c;如邮箱&#xff0c;缩写&#xff0c;以及git commit模板等等。本文就来详细介绍些各个配置如何操作&#xff0c;供参考。 二&#xff0c;配置步骤 2.1 查看当前git的配置 git conf…

python_PyQt5运行股票研究python方法工具V1.1_增加表格展示控件

承接 【python_PyQt5运行股票研究python方法工具V1.0】 地址 python_PyQt5运行股票研究python方法工具V1.0_程序猿与金融与科技的博客-CSDN博客 目录 结果展示&#xff1a; 代码&#xff1a; 示例py文件代码&#xff08;计算股票日横截面数据&#xff09; 参数json文件 表…

nginx代理请求到内网不同服务器

需求&#xff1a;之前用的是frp做的内网穿透&#xff0c;但是每次电脑断电重启&#xff0c;路由或者端口会冲突&#xff0c;现在使用汉土云盒替换frp。 需要把公网ip映射到任意一台内网服务器上&#xff0c;然后在这台内网服务器上用Nginx做代理即可访问内网其它服务器&#xf…

自然语言处理技术:NLP句法解析树与可视化方法

自然语言处理(Natural Language Processing,NLP)句法解析树是一种表示自然语言句子结构的图形化方式。它帮助将句子中的每个词汇和短语按照语法规则连接起来,形成一个树状结构,以便更好地理解句子的语法结构和含义。句法解析树对于理解句子的句法关系、依存关系以及语义角…

爬虫逆向实战(四)--猿人学第一题

一、数据接口分析 主页地址&#xff1a;猿人学第一题 1、抓包 当我们打开F12时会发现直接debugger了&#xff0c;是一个无限debugger&#xff0c;我们直接右键debugger那一行&#xff0c;然后选择“一律不再此处暂停”就可以了 通过抓包可以发现登录接口是api/match/1 2、…

【FAQ】安防监控视频云存储平台EasyNVR频繁离线的原因排查与解决

有用户反馈&#xff0c;在使用EasyNVR时会出现通道频繁离线的情况。针对该反馈我们立即进行了排查。 安防视频监控汇聚EasyNVR视频集中存储平台&#xff0c;是基于RTSP/Onvif协议的安防视频平台&#xff0c;可支持将接入的视频流进行全平台、全终端分发&#xff0c;分发的视频流…

Docker容器与虚拟化技术:Docker镜像创建、Dockerfile实例

目录 一、理论 1.Docker镜像的创建方法 2.Docker镜像结构的分层 3.Dockerfile 案例 4.构建Systemctl镜像&#xff08;基于SSH镜像&#xff09; 5.构建Tomcat 镜像 6.构建Mysql镜像 二、实验 1.Docker镜像的创建 2. Dockerfile 案例 3.构建Systemctl镜像&#xff08;…

DAMO-YOLO:实时目标检测设计的报告

ReadPaperhttps://readpaper.com/pdf-annotate/note?pdfId4748421678288076801eId1920373270663763712 Abstract 在本报告中&#xff0c;我们提出了一种快速准确的目标检测方法&#xff0c;称为DAMO-YOLO&#xff0c;它比最先进的YOLO系列实现了更高的性能。DAMO-YOLO 通过…

图数据库_Neo4j_Centos7.9安装Neo4j社区版3.5.4_基于jdk1.8---Neo4j图数据库工作笔记0011

首先上传安装包,到opt/soft目录 然后看一下jdk安装的是什么版本的,因为在neo4j 4以后就必须要用jdk11 以上的版本,我这里还用着jdk1.8 所以 我这里用3.5.4的版本 关于下载地址: https://dist.neo4j.org/neo4j-community-3.5.4-unix.tar.gz 然后再去解压到/opt/module目录下 …

C语言刷题训练DAY.3

1.ASCII码 解题思路&#xff1a; 这里直接以字符的形式打印就行&#xff1a; 解题代码&#xff1a; #include<stdio.h> int main() {printf("%c%c%c%c%c%c%c%c%c%c%c%c", 73, 32, 99, 97, 110, 32, 100, 111, 32, 105, 116, 33);return 0; } 2.出生日期输…

bigemap如何添加mapbox地图?

第一步 打开浏览器&#xff0c;找到你要访问的地图的URL地址&#xff0c;并且确认可以正常在浏览器中访问&#xff1b;浏览器中不能访问&#xff0c;同样也不能在软件中访问。 以下为常用地图源地址&#xff1a; 天地图&#xff1a; http://map.tianditu.gov.cn 包含&…