• C++中限制对象的申请


    最近阅读Mitsuba的架构,有一个挺有意思的设计,开始没看明白。

    下面,我把限制对象的申请分两个方面讲述:

    1.限制对象在堆/栈上申请;

    2.限制对象申请的个数。

    //所有的资料,都可以在《more effective c++》上找到


    有一个基类Object,它的析构函数是protected访问权限的。并且,所有继承Object的类,都需要实现一个自己的protected的析构函数。

    Mitsuba还特意解释了,这是为了防止在stack上构建Object的对象

    这是怎么回事呢?

    在栈上构建的对象有什么特点呢?首先,在定义对象的地方会自动构造,并在生命周期结束时自动析构。所以,只要让那些被隐式调用的构造动作和析构动作不合法,就可以了“

    采用protected的目的是为了能够让类能够正常的被继承。但是!要保持子类也不能在栈上申请对象,必须保持子类的析构函数也是protected/private(若是private子类不能被继承,更多信息查看 http://www.cnblogs.com/wangpei0522/p/4460425.html)

    我们把析构函数设为了不可访问的protected/private,直接调用delete操作符释放资源不会通过编译的!

    为此,我们必须增加一个成员函数,在成员函数中使用delete释放资源。因为在成员函数内部,类的成员变得总是可见,所以delete能够成功执行。(Mitsuba中通过智能指针的方式释放资源。非常巧妙的设计)

     与防止在stack上构建对象的设计所对应的方案是

    防止在heap上构建对象

    亲爱的朋友,你肯定能想到设置operator new()的访问权限设置为protected/private,是吧?

    可是有一个问题:

    class onlyStack{
    protected:
        void* operator new (size_t s)
        {
    
        }
        void operator delete(void* ptr)
        {
    
        }
    private:
        int base_data;
    };
    
    class sets{
    private:
        onlyStack s;
    };
    sets* sets_array = new sets[100];

    上面的代码中,sets_array的定义语句发生了如下过程:

    调用sets的operator new申请了一块heap上的内存,然后调用调用sets的构造函数,sets的构造函数再调用了onlyStack的构造函数。全程没有用到onlyStack的operator new。

    我们并没有很好的办法解决这个问题,详见《more effective C++》 #27条款

    ^.^


    限制对象的个数

    什么是限制对象的个数?

    首先,如果我们限制对象可申请的个数为0的时,也就等价于不能申请对象。

    每当产生一个对象,它的构造函数都会被调用,所以,如果我们声明它的构造函数为private,此对象便不能显示申请(这里的显示申请意味着,我们可以通过别的方式申请它,比如静态成员函数调用了构造函数,此成员函数就能申请此对象)。

    还有什么?是的,抽象类也不能申请对象。我们可以定义一个纯虚函数,此对象就成为抽象类,便不能申请对象。

    接下来,我们限制对象可申请的个数为1的时,也就是大名鼎鼎的单例模式。

    继续扩展,我们限制对象可申请的个数为k,k是大于1的正整数。注意,此时的语义和前面的两个不太一样。可申请个数为0和1,只会出现不能申请和每次申请都只会那唯一的一个对象。

    也就是说,当我们申请的对象个数大于k的时候,会出现错误,或者处理错误的行为,而不是返回已经存在的k个对象中的某一个。

    简单说明下原理,我们在类中增加一个计数的数据成员,每次构造函数被调用就加一,析构函数被调用就减一。如果构造函数发现当前的计数成员已经等于最大值k,跳转到处理错误的情况。

    在《more effective c++》的条款26有详细的讲解,但是,我觉得他讲得很繁琐,特别是考虑继承的情况。被继承后,应该要根据具体的应用环境来确定计数。

    记得借鉴的是,通过private继承一个base counting class,该class是一个template类,为每个需要计数的class生成一套代码。


    以上。

  • 相关阅读:
    WebAssembly API & MDN All In One
    Apple iPhone 14 Pro 药丸设计看不懂,药丸上面那条屏幕缝隙完全没有用处呀?
    API 调试工具 All In One
    macOS Time Machine All In One
    使用 macOS 输入多个空格,会自动添加一个点 bug All In One
    手把手的教你如何使用 Vite 搭建一个 React UI 组件库 All In One
    LeetCode 两数相加算法题解 All In One
    如何把 iPad 作为 Mac 扩展屏幕使用 All In One
    【DEMO】【C/C++】最简单的一种回调函数
    Qt中cvMat与QImage,QPixmap的转换
  • 原文地址:https://www.cnblogs.com/wangpei0522/p/4542223.html
Copyright © 2020-2023  润新知