• C++:delete不完整类型的指针


    简单版

    以下代码编译时会有warning:

    class X;
    
    void foo(X* x) {
        delete x;
    }
    

    在GCC4.1.2下,编译出错信息是:

    warning: possible problem detected in invocation of delete operator:
    warning: ‘x’ has incomplete type
    warning: forward declaration of ‘struct X’
    note: neither the destructor nor the class-specific operator delete will be called, even if they are declared when the class is defined.
    

    这是因为在foo里,编译器看不到X的完整类型,没办法确定两件事情:

    1. X有没有自定义的析构函数(准确的说,有没有non-trivial的析构函数)。
    2. X有没有自定义的operator delete函数。

    在不确定这两件事情的情况下,编译器只能按最普通的方式去处理delete x

    1. 不调用任何析构函数。
    2. 调用全局的operator delete,通常来说就是直接释放内存。

    日常版

    有一个我们平常会遇到的场景,就会触发上面这个问题。

    以下是由三个文件组成的一个工程,其中用到了'pImpl'方法来隐藏实现,因此在接口类中放了一个std::auto_ptr,很简单:

    // test.h
    #include <memory>
    
    class A {
        class Impl;
    public:
        A();
        void Func();
    private:
        std::auto_ptr<Impl> mImpl;
    };
    
    // test.cpp
    #include "test.h"
    #include <iostream>
    
    class A::Impl {
    public:
        void Func() {
            std::cout << "Func" << std::endl;
        }
    };
    
    A::A(): mImpl(new Impl) {}
    
    void A::Func() {
        mImpl->Func();
    }
    
    // main.cpp
    
    #include "test.h"
    
    int main() {
        A a;
        a.Func();
    }
    

    看起来很正常,但编译时有warning:

    $g++ test.cpp main.cpp
    In destructor ‘std::auto_ptr<_Tp>::~auto_ptr() [with _Tp = A::Impl]’:
    test.h:4:   instantiated from here
    warning: possible problem detected in invocation of delete operator:
    warning: invalid use of undefined type ‘struct A::Impl’
    test.h:5: warning: forward declaration of ‘struct A::Impl’
    note: neither the destructor nor the class-specific operator delete will be called, even if they are declared when the class is defined.
    

    和前面说的warning信息完全一致,看起来也是在调用delete时出的问题。但哪里调用了delete呢?

    答案是std::auto_ptr

    上面的代码中,我们没有给class A手动写一个析构函数,因为编译器自动生成的析构函数就是我们要的:析构时把mImpl析构掉。

    那么自动生成的析构函数长什么样子呢?大概是:

    A::~A() {
        mImpl.~std::auto_ptr<Impl>();
    }
    

    展开了基本就是一句delete

    A::~A() {
        delete mImpl._M_ptr;
    }
    

    这个析构函数的位置在哪呢?C++标准里说会把自动生成的类成员函数放在类的定义中,那么就是在test.h中。

    问题清楚了:我们在编译main.cpp时,看不到A::Impl的完整定义,但却有一个自动生成的A::~A,其中delete了一个不完整的类对象!

    解法

    手动写一个A的析构函数,位置要在能看到A::Impl完整定义的地方,也就是test.cpp:

    ```cpp
    // test.h
    #include <memory>
    
    class A {
        class Impl;
    public:
        A();
        ~A();
        void Func();
    private:
        std::auto_ptr<Impl> mImpl;
    };
    
    // test.cpp
    #include "test.h"
    #include <iostream>
    
    class A::Impl {
    public:
        void Func() {
            std::cout << "Func" << std::endl;
        }
    };
    
    A::A(): mImpl(new Impl) {}
    A::~A() {}
    
    void A::Func() {
        mImpl->Func();
    }
    

    相关文献

  • 相关阅读:
    .net中对象序列化技术
    new、virtual、override
    如何检测指定的Windows服务是否启动
    c#中的GetUpperBound,GetLowerBound方法
    C#.net中的rank方法
    实现MD5算法
    用C#实现DES加密解密封装
    [转]JSP或servlet中(以及上传下载文件)中文乱码或不显示的解决方案
    [转]runOnUiThread 、 Handler 对比(一)
    [转]使用popBackStack()清除Fragment
  • 原文地址:https://www.cnblogs.com/fuzhe1989/p/7763523.html
Copyright © 2020-2023  润新知