记录一个QScopedPointer forward declared 的编译错误

记录一个QScopedPointer forward declared 的编译错误

使用QScopedPointer内包含一个前置声明的变量时,仍然发生一个编译错误

编译错误显示(博主这个类名叫SASelectRegionEditor,使用IMPL模式实现)

D:\Qt\Qt5.7.0\5.7\mingw53_32\include\QtCore\qscopedpointer.h:57: error: invalid application of 'sizeof' to incomplete type 'SASelectRegionEditorPrivate'
         typedef char IsIncompleteType[ sizeof(T) ? 1 : -1 ];
                                              ^

错误定位到Qt源码的这个位置:

template <typename T>
struct QScopedPointerDeleter
{
    static inline void cleanup(T *pointer)
    {
        // Enforce a complete type.
        // If you get a compile error here, read the section on forward declared
        // classes in the QScopedPointer documentation.
        typedef char IsIncompleteType[ sizeof(T) ? 1 : -1 ];
        (void) sizeof(IsIncompleteType);

        delete pointer;
    }
};

上面注释很明确说了需要进行前置声明,但我明明已经进行了前置声明了,仍然会有这个编译错误:

class SASelectRegionEditorPrivate;
///
/// \brief 用于控制选区数据的编辑器
///
class SA_COMMON_UI_EXPORT SASelectRegionEditor : public SAAbstractPlotEditor
{
    Q_OBJECT
    QScopedPointer< SASelectRegionEditorPrivate > d_ptr;
public:
    SASelectRegionEditor(SAChart2D *parent);
    ...

明明已经有class SASelectRegionEditorPrivate;但还是出现这个编译错误

后来折腾来折腾去,最后发现,居然把虚析构函数加上就可以编译通过

class SASelectRegionEditorPrivate;
///
/// \brief 用于控制选区数据的编辑器
///
class SA_COMMON_UI_EXPORT SASelectRegionEditor : public SAAbstractPlotEditor
{
    Q_OBJECT
    QScopedPointer< SASelectRegionEditorPrivate > d_ptr;
public:
    SASelectRegionEditor(SAChart2D *parent);
    ~SASelectRegionEditor();
    ...

原因解决但不明白原理

Qt智能指针--QScopedPointer ⽂章⽬录 概述 前⼀篇⽂章我们详细的介绍了的⽤法,那么,这⾥继续总结Qt的另⼀个智能指针QScopedPointer的⽤法。 QScopedPointer和C++中的智能指针std::unique_ptr其概念是⼀样的,它包装了new操作符在堆上分配的动态对象,能够保证动态创建 的对象在任何时候都可以被正确地删除。但它有更严格的所有权,并且不能转让,⼀旦获取了对象的管理权,你就⽆法再从它那⾥取回来。 也就是说,只要出了作⽤域,指针就会被⾃动删除,因为它的拷贝构造和赋值操作都是私有的,与QObject及其派⽣类风格相同。 QScopedPointer ⾸先我们来看⼀个官⽅⽰例: 没有使⽤智能指针: void myFunction(bool useSubClass) { MyClass *p = useSubClass ? new MyClass() : new MySubClass; QIODevice *device = handsOverOwnership(); if (m_value > 3) { delete p; delete device; return; } try { process(device); } catch (...) { delete p; delete device; throw; } delete p; delete device; } 上⾯的写法,稍有不慎就会导致内存泄露,但是如果使⽤智能指针,就会变得很简单了: void myFunction(bool useSubClass) { QScopedPointer<MyClass> p(useSubClass ? new MyClass() : new MySubClass); QScopedPointer<QIODevice> device(handsOverOwnership()); if (m_value > 3) return; process(device); } 注意:因为拷贝构造和赋值操作私有的,所以不能⽤作容器的元素。 const 限制 C ++指针的const限定也可以⽤QScopedPointer表⽰: const QWidget *const p = new QWidget(); // 等同于: const QScopedPointer<const QWidget> p(new QWidget()); QWidget *const p = new QWidget(); // 等同于: const QScopedPointer<QWidget> p(new QWidget()); const QWidget *p = new QWidget(); // 等同于: QScopedPointer<const QWidget> p(new QWidget()); 考虑⼀种情况 上⾯说到,使⽤QScopedPointer智能指针动态创建的对象,⼀旦出了作⽤域就会 被⾃动释放并置空,那么如果需要函数返回值怎么办 呢? ⽐如下⾯这种情况: QLabel * createLabel() { QScopedPointer<QLabel> pLabel(new QLabel()); // return pLabel.data(); //invalid return pLabel.take(); //valid } int main(int argc, char *argv[]) { QApplication a(argc, argv); QScopedPointer<QLabel> p1(createLabel()); p1->setText("hello"); p1->show(); return a.exec(); } 注意,我们在createLabel()函数中创建label对象并返回时,不能使⽤data(),⽽要使⽤take(); 因为 T *QScopedPointer::data() const返回指向对象的常量指针,QScopedPointer仍拥有对象所有权。 所以通过data()返回过后就被 ⾃动删除了,从⽽导致mian函数中的p1变成了野指针,程序崩溃。 ⽽使⽤T *QScopedPointer::take()也是返回对象指针,但QScopedPointer不再拥有对象所有权,⽽是转移到调⽤这个函数的caller,同 时QScopePointer对象指针置为NULL。 另外还有⼀个函数要注意。 void QScopedPointer::reset(T *other = Q_NULLPTR):delete⽬前指向的对象,调⽤其析构函数,将指针指向另⼀个对象other,所有 权转移到
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

尘中远

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值