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

简介: 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; //基类是 QArrayData
    inline 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 header
    void *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 two
    Q_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中相关的编码相关函数,这块也是一个细节,待整理

目录
相关文章
|
5月前
|
Kubernetes jenkins 持续交付
从代码到k8s部署应有尽有系列-java源码之String详解
本文详细介绍了一个基于 `gitlab + jenkins + harbor + k8s` 的自动化部署环境搭建流程。其中,`gitlab` 用于代码托管和 CI,`jenkins` 负责 CD 发布,`harbor` 作为镜像仓库,而 `k8s` 则用于运行服务。文章具体介绍了每项工具的部署步骤,并提供了详细的配置信息和示例代码。此外,还特别指出中间件(如 MySQL、Redis 等)应部署在 K8s 之外,以确保服务稳定性和独立性。通过本文,读者可以学习如何在本地环境中搭建一套完整的自动化部署系统。
77 0
|
2月前
|
C语言 C++ 容器
【c++丨STL】string模拟实现(附源码)
本文详细介绍了如何模拟实现C++ STL中的`string`类,包括其构造函数、拷贝构造、赋值重载、析构函数等基本功能,以及字符串的插入、删除、查找、比较等操作。文章还展示了如何实现输入输出流操作符,使自定义的`string`类能够方便地与`cin`和`cout`配合使用。通过这些实现,读者不仅能加深对`string`类的理解,还能提升对C++编程技巧的掌握。
78 5
|
4月前
|
编解码 开发工具 UED
QT Widgets模块源码解析与实践
【9月更文挑战第20天】Qt Widgets 模块是 Qt 开发中至关重要的部分,提供了丰富的 GUI 组件,如按钮、文本框等,并支持布局管理、事件处理和窗口管理。这些组件基于信号与槽机制,实现灵活交互。通过对源码的解析及实践应用,可深入了解其类结构、布局管理和事件处理机制,掌握创建复杂 UI 界面的方法,提升开发效率和用户体验。
207 13
|
4月前
|
Windows
QT源码拾贝6-11(qwindowswindow)
这篇文章深入探讨了Qt源码中与窗口激活相关的函数,QDebug运算符重载,vscode的变量提示,Windows常用类型名,获取所有窗体的方法,以及QSharedPointer智能指针的使用。
102 0
QT源码拾贝6-11(qwindowswindow)
|
4月前
|
存储 Java C++
QT源码拾贝0-5(qimage和qpainter)
这篇文章介绍了在Qt源码中qimage和qpainter的使用,包括线程池的使用、智能指针的存储、std::exchange函数的应用、获取类对象的方法以及QChar字节操作。
QT源码拾贝0-5(qimage和qpainter)
|
5月前
|
存储 C++
【C++】C++ 基于QT实现散列表学生管理系统(源码+数据+课程论文)【独一无二】
【C++】C++ 基于QT实现散列表学生管理系统(源码+数据+课程论文)【独一无二】
116 1
【C++】C++ 基于QT实现散列表学生管理系统(源码+数据+课程论文)【独一无二】
|
5月前
|
存储 算法 C++
【C++】C++ QT实现Huffman编码器与解码器(源码+课程论文+文件)【独一无二】
【C++】C++ QT实现Huffman编码器与解码器(源码+课程论文+文件)【独一无二】
141 4
|
5月前
|
存储 编译器 C语言
C++ --> string类模拟实现(附源码)
C++ --> string类模拟实现(附源码)
83 4
|
5月前
从源码角度分析Qt元对象系统2
从源码角度分析Qt元对象系统
62 0
|
5月前
|
存储
从源码角度分析Qt元对象系统1
从源码角度分析Qt元对象系统
90 0