More Effective C++:Item 27

来源:互联网 发布:张北云计算产业园在哪 编辑:程序博客网 时间:2024/04/30 08:58

温习More Effective C++,对于Item 27:要求或禁止在堆中产生对象,整理思路于此文。

编译期控制

通过禁用定义对象所需的条件,即可在编译期阻止对象的定义。

  • 定义堆对象所需的条件
class operator new 构造函数 析构函数  独立对象  非必须 不需要,可定义伪构造函数 不需要,可定义伪析构函数 成员直接对象 不需要,整体类定义即可 不需要,可定义伪构造函数 不需要,可定义伪析构函数 成员指针对象 不需要,整体类定义即可 不需要,可定义伪构造函数 不需要,可定义伪析构函数  基类对象  不需要,派生类定义即可 public / protected public / protected
  • 定义非堆对象所需的条件

|||||
|独立非堆对象|不需要|public|public|
|成员非堆对象|不需要|public|public|
|基类非堆对象|不需要|public|public|


注意其中一点,作为成员堆对象,其可以是直接对象也可以是指针对象。而作为成员非堆对象,则只能是直接对象。

通过上表不难得出以下结论:

要求对象在堆中

禁用public构造或析构函数即可使得独立对象和成员对象无法定义在非堆位置,而相应提供伪构造或析构函数就不会影响其在堆中的定义。

然而对于基类对象却没有什么好的办法,因为无论是否在堆中,其定义条件都是相同的——public或protected的构造和析构函数。若声明构造或析构函数为private,基类对象的定义就会被完全禁止,也就是说该类将无法作为基类。

// 数字类。class Number{public:    // 提供伪构造函数。    static Number* MakeInstance() { return new Number; }     virtual ~Number() {}protected:    // 将构造函数声明为protectedNumber() {} };//==============================================================================// 独立对象。//==============================================================================void DefineIndependentObject(){    //==========================================================================    // 定义在堆中:正确。    //==========================================================================    Number* heapObject = Number::MakeInstance();    delete heapObject;    //==========================================================================    // 定义在栈中:错误。    //==========================================================================    Number nonheapObject;}//==============================================================================// 成员对象。//==============================================================================void DefineMemberObject(){    //==========================================================================    // 定义在堆中:正确。    //==========================================================================    {        // 财产类包含一个数字类指针。        class Asset        {        public:            Asset() : value( Number::MakeInstance() ) {}            ~Asset() { delete value; }        private:            Number* value;        };        Asset* heapObject = new Asset;        delete heapObject;    }    //==========================================================================    // 定义在栈中:错误。    //==========================================================================    {        // 财产类包含一个数字类。        class Asset { private: Number value; };        Asset nonheapObject;    }}//==============================================================================// 子类对象//==============================================================================void DefineSubclassObject(){    // 负数类派生自数字类。    class NegativeNumber : public Number {};    //==========================================================================    // 定义在堆中:正确。    //==========================================================================    NegativeNumber* heapObject = new NegativeNumber;    delete heapObject;    //==========================================================================    // 定义在栈中:正确。    //==========================================================================    NegativeNumber nonheapObject;}

禁止对象在堆中

只需禁用public class new即可禁止独立对象定义在堆中,并且不会对其在非堆位置中的定义产生影响。

然而对于成员对象和基类对象却又不存在什么好的办法,因为只有定义了public构造和析构函数,它们才能被定义在非堆位置,然而这也会使得它们能被定义在堆中。同样的,若是将构造或析构函数定义为private,那么它们的定义将会被完全禁止。

#include <new>class Number{private:    static void* operator new( std::size_t ) throw() { return nullptr; }};//==============================================================================// 独立对象。//==============================================================================void DefineIndependentObject(){    //==========================================================================    // 定义在堆中:错误。    //==========================================================================    Number* heapObject = new Number;    delete heapObject;    //==========================================================================    // 定义在栈中:正确。    //==========================================================================    Number nonheapObject;}

运行期控制

通过堆对象和非堆对象的不同创建流程来进行控制。其不同之处只有一点:创建堆对象时class operator new会被调用。然而,首先,这一点只对独立对象管用:基类堆对象和成员堆对象的class operator new不一定被调用。

#include <new>#include <iostream>class Number{public:    static void* operator new( std::size_t ) throw()     {        std::cout << "class operator new for Number" << std::endl;    }};class NegativeNumber : public Number{public:    static void* operator new( std::size_t ) throw()     {        std::cout << "class operator new for NegativeNumber" << std::endl;    }};class Asset { Number value; };int main(){    // 独立堆对象的class operator new被调用。    Number* independentObject = new Number;    delete independentObject;    // 看,基类堆对象的则没有被调用。    NegativeNumber* baseObject = new NegativeNumber;    delete baseObject;    // 看,子类堆对象的也没有被调用。    Asset* memberObject = new Asset;    delete memberObject;    return 0;}

然后,即使是对于独立对象,它也不怎么好用,具体请参考More Effective C++ Item27。

总结

控制对象的内存位置比较困难,能够完美实现的只有:
1. 要求独立对象和成员对象在堆中。
2. 禁止独立对象在对象。

0 0
原创粉丝点击