qscopedpointer
qscopedpointer
是 qt 提供的一个智能指针,主要用于简化资源管理,防止内存泄漏和悬挂指针问题。它属于 qt 的内存管理工具,能够自动处理对象的生命周期,确保对象在超出作用域时被销毁。qscopedpointer
是基于 c++11 标准中的 std::unique_ptr
实现的,但它具有 qt 的特点,通常用于局部对象的管理。
- 自动删除对象:当
qscopedpointer
超出作用域时,它会自动释放所持有的对象。这意味着无需手动delete
对象。 - 不能复制:
qscopedpointer
不支持复制操作,防止发生意外的多个指针指向同一个对象的问题。 - 所有权转移:可以使用
reset()
或通过构造函数将qscopedpointer
的所有权转移给另一个qscopedpointer
。
1. 自动删除对象
qscopedpointer
最常见的用法是在函数或局部作用域内管理动态分配的对象。在作用域结束时,qscopedpointer
自动销毁对象,无需显式调用 delete
。
#include <qscopedpointer> #include <qdebug> class myclass { public: myclass() { qdebug() << "myclass constructed"; } ~myclass() { qdebug() << "myclass destructed"; } }; void testscopedpointer() { qscopedpointer<myclass> ptr(new myclass); // 当函数返回时,ptr 超出作用域,对象会被自动销毁 } // 在这里,myclass 对象会被自动删除
2. 转移所有权
qscopedpointer
不支持复制操作,但可以通过 reset()
或构造函数转移所有权。这样,qscopedpointer
可以在不同的作用域之间传递资源。
#include <qscopedpointer> #include <qdebug> class myclass { public: myclass() { qdebug() << "myclass constructed"; } ~myclass() { qdebug() << "myclass destructed"; } }; void transferownership() { qscopedpointer<myclass> ptr1(new myclass); // 将所有权从 ptr1 转移到 ptr2 qscopedpointer<myclass> ptr2(ptr1.take()); // 现在 ptr1 不再拥有 myclass 对象,ptr2 拥有它 // ptr1 不再指向对象,但对象仍然存在,由 ptr2 管理 } // 在这里,ptr2 超出作用域时,myclass 对象会被自动删除
3. 管理私有数据
在 qt 的许多类中,私有数据(通常是一个包含实现细节的类)被封装在一个 qscopedpointer
中。这样可以确保私有数据在类的析构函数中自动释放,同时保持代码的简洁性和安全性。
示例:qfile
类
class qfileprivate : public qiodeviceprivate { // 私有数据成员 }; class qfile : public qiodevice { public: qfile(); ~qfile(); private: qscopedpointer<qfileprivate> d_ptr; };
在这个例子中,qfile
类使用 qscopedpointer
来管理 qfileprivate
对象。当 qfile
对象析构时,qscopedpointer
会自动删除 qfileprivate
对象,确保内存被释放。
qsharedpointer
qsharedpointer
是通过引用计数来管理对象的生命周期的,多个 qsharedpointer
对象可以共享同一个资源。每当 qsharedpointer
的拷贝构造或赋值操作发生时,引用计数会增加,而当一个 qsharedpointer
被销毁时,引用计数会减少。当引用计数降到 0 时,所指向的对象会自动被删除。
#include <qsharedpointer> #include <qdebug> class myclass { public: void print() { qdebug() << "hello from myclass!"; } }; int main() { // 创建 qsharedpointer 对象,管理 myclass 对象的生命周期 qsharedpointer<myclass> ptr1(new myclass); // 创建另外一个 qsharedpointer,并共享 ptr1 所管理的对象 qsharedpointer<myclass> ptr2 = ptr1; // 使用 ptr1 和 ptr2 都能访问同一个对象 ptr1->print(); ptr2->print(); // 不需要手动释放内存,当最后一个 qsharedpointer 被销毁时,myclass 对象会自动删除 return 0; }
关键特性
- 引用计数:
qsharedpointer
通过引用计数来管理对象的生命周期。每当有新的qsharedpointer
对象指向相同的资源时,引用计数会增加;当某个qsharedpointer
对象销毁时,引用计数会减少。 - 自动销毁:当最后一个引用计数为 1 的
qsharedpointer
被销毁时,指向的对象会被自动删除,从而避免了内存泄漏。 - 线程安全:
qsharedpointer
的引用计数操作是线程安全的,但它本身并不保证被指向的对象本身是线程安全的。如果多个线程访问同一个qsharedpointer
对象,必须确保其他线程同步访问该对象。
注意事项
qsharedpointer
的引用计数机制在某些情况下可能导致循环引用问题,特别是当两个或更多的对象相互持有对方的qsharedpointer
时。此时,即使这些对象不再使用,引用计数也不会降到零,因为它们互相引用,导致对象无法被销毁,从而产生内存泄漏。解决方法:使用
qweakpointer
来打破循环引用。qweakpointer
是一种弱引用,持有一个qsharedpointer
对象,但它不会增加引用计数。当qsharedpointer
被销毁时,qweakpointer
自动变为空指针。- 不要混用裸指针和
qsharedpointer``qsharedpointer
需要确保它是唯一的内存管理者。如果你在程序中同时使用裸指针和qsharedpointer
管理相同的内存,可能会导致双重释放或内存泄漏。因此,避免裸指针与智能指针共享同一资源,确保对象始终由智能指针管理。
qweakpointer
qweakpointer
是 qsharedpointer
的一种补充,它本身不拥有对象的所有权。qweakpointer
仅在 qsharedpointer
的引用计数为非零时提供访问该对象的能力,但不会阻止对象的销毁。换句话说,qweakpointer
允许你引用一个对象而不会使得该对象无法销毁。
qweakpointer
的主要特点:
- 弱引用:
qweakpointer
不增加对象的引用计数,也就是说它不会阻止对象的销毁。 - 防止循环引用:
qweakpointer
解决了qsharedpointer
可能导致的循环引用问题。 - 安全的访问方式:
qweakpointer
可以通过tostrongref()
方法转换为qsharedpointer
,从而安全地访问目标对象。
qweakpointer
和 qsharedpointer
的配合
qweakpointer
通常与 qsharedpointer
一起使用,用于避免循环引用。在有些情况下,两个对象会互相引用,导致它们的引用计数始终不为零,进而导致内存泄漏。qweakpointer
可以打破这个循环引用链,它允许对象 a 持有对象 b 的 qweakpointer
,而对象 b 可以持有对象 a 的 qsharedpointer
,从而确保对象 a 和 b 的生命周期由 qsharedpointer
管理。
qweakpointer
的常见用法
下面是一个使用 qweakpointer
的具体示例:
class b; // forward declaration class a { public: qsharedpointer<b> b; // b的共享指针 }; class b { public: qweakpointer<a> a; // a的弱引用 }; int main() { qsharedpointer<a> a(new a); // 创建a对象 qsharedpointer<b> b(new b); // 创建b对象 a->b = b; // a持有b的共享指针 b->a = a; // b持有a的弱引用 return 0; // 程序退出时,a和b会被自动销毁,避免内存泄漏 }
注意事项
使用qweakpointer时候,一定要使用isnull
判断一下 资源是否释放
qsharedpointer<myclass> shared(new myclass(20)); qweakpointer<myclass> weak(shared); qdebug() << "shared pointer value:" << shared->getvalue(); qdebug() << "weak pointer value:" << weak.data()->getvalue(); shared.clear(); // 删除 shared 指向的对象 // 此时,myclass 对象的引用计数为 0,将被自动删除,而此时 qweakpointer 对象 weak 也为 null。 if (weak.isnull()) { // 判断 weak 是否为 null qdebug() << "weak pointer is null - object has been deleted"; // 执行 } else { qdebug() << "weak pointer is not null - object still exists"; }
qpointer
qpointer
是一个用于指向 qt 对象(例如 qobject
的子类)的模板类,它会自动管理对象的生命周期。当一个 qobject
被销毁时,qpointer
会将其指针设为 nullptr
,这使得程序能够检测到所指向的对象已经被删除,从而避免访问已删除的对象,避免悬空指针问题。qpointer
只能用来管理 qobject
或其子类的对象。如果你需要管理其他类型的对象,可以考虑使用其他智能指针,如 std::shared_ptr
或 std::unique_ptr
。
#include <qpointer> #include <qpushbutton> #include <qvboxlayout> #include <qwidget> #include <qdebug> int main(int argc, char *argv[]) { qcoreapplication a(argc, argv); qwidget window; qvboxlayout *layout = new qvboxlayout(&window); qpushbutton *button = new qpushbutton("click me"); qpointer<qpushbutton> pbutton(button); layout->addwidget(button); window.show(); qobject::connect(button, &qpushbutton::clicked, [&] { if (pbutton) { qdebug() << "button exists, text:" << pbutton->text(); } else { qdebug() << "button has been deleted"; } }); // 模拟按钮删除 qobject::connect(button, &qpushbutton::clicked, [&] { delete button; }); return a.exec(); }
到此这篇关于qt 智能指针的具体使用的文章就介绍到这了,更多相关qt 智能指针内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论