QSharedDataPointer似乎是在复制对象,而不是增加引用计数

编程语言 2026-07-08

我一直在跟随关于QSharedDataPointer的教程,发现当对包含QSharedDataPointer的 Employee调用拷贝构造函数时,QSharedDataPointer构造器p{other.p} 在某种程度上似乎调用了EmployeeData(QSharedData的子类)的拷贝构造函数,导致QSharedData对象被复制了一份,而不是简单地给QSharedData增加引用计数。

我对在调用QSharedDataPointer拷贝构造函数p{other.p} 时到底发生了什么,以及它是如何链式调用EmployeeData(const EmployeeData& other) 的感到困惑?

谢谢

#include <QtCore/QSharedData>
#include <QtCore/QSharedDataPointer>
#include <QtCore/QString>
#include <QtCore/QDebug>


class EmployeeData: public QSharedData {
public:
    int e_id = -1;
    QString e_name;

    EmployeeData(): e_id{-1} {
        qInfo()<<"Default EmployeeData created.";
    };
    EmployeeData(int id, const QString& name): e_id(id), e_name(name) {
        qInfo()<<"EmployeeData "<<e_id<<": "<<e_name<<" created.";
    }
    EmployeeData(const EmployeeData& other): QSharedData(other), e_id(other.e_id), e_name(other.e_name) {
        qInfo()<<"EmployeeData "<<e_id<<": "<<e_name<<" copied.";
    }

    ~EmployeeData() {
        qInfo()<<e_id<<": "<<e_name<<" deconstructed.";
    }
};

class Employee {
    QSharedDataPointer<EmployeeData> p;
public:
    Employee() {
        p = new EmployeeData();
    }
    Employee(int id, const QString& name) {
        p = new EmployeeData(id, name);
    }
    Employee(const Employee& other): p{other.p} {
        qInfo()<<"Copy QSDPointer for "<<p->e_id<<": "<<p->e_name;
    }

    ~Employee() {
        qInfo()<<"SmartPointer "<<p->e_id<<", "<<p->e_name<<", destroyed";
    }
};

当用下面这个测试函数进行测试时

void test_e() {
    Employee e1 (1, "Rupert");
    Employee e2 (2, "Albrecht");
    Employee e3 = e1;
    Employee e4 = e2;
}

int main() {
    test_e();
    return 0;
}

它给出了以下日志:

EmployeeData 1: "Rupert" 已创建。

EmployeeData 2: "Albrecht" 已创建。

EmployeeData 1: "Rupert" 已拷贝。

Copy QSDPointer for 1: "Rupert"

EmployeeData 2: "Albrecht" 已拷贝。

Copy QSDPointer for 2: "Albrecht"

SmartPointer 2, "Albrecht" 已销毁

2: "Albrecht" 已析构。

SmartPointer 1, "Rupert" 已销毁

1: "Rupert" 已析构。

SmartPointer 2, "Albrecht" 已销毁

2: "Albrecht" 已析构。

SmartPointer 1, "Rupert" 已销毁

1: "Rupert" 已析构。

It

解决方案

问题出在你访问指针的方式。看看拷贝构造函数

    Employee(const Employee& other): p{other.p} {
        qInfo()<<"Copy QSDPointer for "<<p->e_id<<": "<<p->e_name;
    }

你访问 p->e_id。在这个上下文中,p 是一个可变的 QSharedDataPointer,这意味着对它解引用会得到对象的可变引用。智能指针无法知道你是想通过该对象引用进行读取还是写入。因此它必须为了实现写时复制语义而进行拷贝。

这在 文档中有说明:

T *QSharedDataPointer::operator->()
提供对共享数据对象成员的访问。此函数调用 detach()

经验法则:

  • 除非你想要产生拷贝,否则不要在非常量方法中访问 QSharedDataPointer
  • 对于来自非常量方法的常量访问,要么调用 pointer.constData(),要么使用常量引用
  • 尽可能将指针本身声明为const;也就是说如果你从不需要对数据进行非常量访问,且不需要移动构造或赋值(例如在 QObjects 中,因为那些本来就不可移动)
  • 如需更好的控制,请使用 QExplicitlySharedDataPointer

你的构造函数应该像这样:

    Employee(const Employee& other): p{other.p} {
        const auto& p = this->p;
        qInfo()<<"Copy QSDPointer for "<<p->e_id<<": "<<p->e_name;
    }

在析构函数中你也有同样的问题。

    ~Employee() {
        const auto& p = this->p;
        qInfo()<<"SmartPointer "<<p->e_id<<", "<<p->e_name<<", destroyed";
    }
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章