美文网首页C++ 杂记
C++ 如何保证一个对象只能在堆上生成?

C++ 如何保证一个对象只能在堆上生成?

作者: 赵者也 | 来源:发表于2020-06-19 22:40 被阅读0次

    因为 C++ 是静态绑定语言。在编译过程中,所有的非虚函数调用都必须被解析完成。即使是虚函数,也需检查可访问性。

    当在栈上生成对象时,对象会自动析构,此时对析构函数的需求是必须的,因此析构函数必须是可以访问。而堆上生成的对象,由于其具体的析构时机由开发者来控制,此时对析构函数的需求不是必须的。

    上面是保证了不能在栈上生成对象的原理,接下来我们需要证明我们确实只能在堆上生成它。下面是一个测试的示例(使用了 Qt Creator IDE 及部分 Qt 类):

    #include <QCoreApplication>
    #include <QDebug>
    
    namespace {
    const QString OUTPUT_INFO_SATRT("CreatNewOnly===debug output:");
    }
    
    class CreatNewOnly
    {
        ~CreatNewOnly() {
            qDebug() << OUTPUT_INFO_SATRT << "~CreatNewOnly() called";
        }
    public:
        CreatNewOnly() {
            qDebug() << OUTPUT_INFO_SATRT << "CreatNewOnly() called";
        }
    
        void destroy() {
            delete this;
            qDebug() << OUTPUT_INFO_SATRT << "destroy() called";
        }
    };
    
    int main(int argc, char *argv[])
    {
        QCoreApplication a(argc, argv);
    
    //    CreatNewOnly test001;
        CreatNewOnly* test002 = new CreatNewOnly;
    //    delete test002;
        test002->destroy();
        test002 = nullptr;
    
        return a.exec();
    }
    

    其输出如下图所示:

    2020-04-26 13-51-04屏幕截图.png

    这里 CreatNewOnly 与一般对象唯一的区别是它的析构函数是私有的。

    我们知道 delete 操作会调用析构函数,但是因为 CreatNewOnly 的析构函数是私有的,所以直接通过 delete 操作指针对象是不能通过编译的。那么我们该如何释放 new 出来的对象呢?我们可以像示例代码一样提供一个公有的成员函数,用于完成 delete 操作。在成员函数中,私有的析构函数是可以访问的。此时的 detele 操作也是可以编译通过的。

    下面是注释掉的代码显示的编译问题:

    创建栈对象的错误提示信息 delete 操作的错误提示信息

    使用场景举例:

    1. 禁止用户在栈内存空间内创建此类型的对象。要创建对象,只能用 new 在堆上进行。
    2. 我们设计的类需要在析构时必须要执行一些操作,但是又担心类的使用者不会主动去执行这些操作时。

    相关文章

      网友评论

        本文标题:C++ 如何保证一个对象只能在堆上生成?

        本文链接:https://www.haomeiwen.com/subject/mjsdwhtx.html