More Effective C++读书笔记:条款26

Aki 发布于 2022-10-21 316 次阅读


26限制某个class所能产生的对象数量:

只允许产生0个:

  • 每一个对象产生,就有一个构造函数被调用,将其声明为private即可阻止对象的生成
  • 注意构造函数有四种:无参,有参构造函数和拷贝构造函数,移动构造函数。移动构造函数编译器不会自动帮我们生成,而且也只有在使用了std::move()的时候才会调用。
class obj
{
private:
    obj(){}
    obj(const obj&rhs){}
    obj(obj&& rhs)noexcept{}
};

只允许产生1个:

主要方法:声明一个static对象,表示只有一个对象被产生出来,通过一个函数返回一个引用或指针指向某隐藏的对象两种途径:1、(class static)在类中内含一个static对象(单例模式),2、(function static)在全局函数中内含一个static局部变量

function static

  • 三个成分:
    1、构造私有化 ,抑制对象产生
    2、全局函数声明为类的友元函数,不受private约束
    3、内含一个static变量,并返回它的引用,意味着只有一个对象产生
class obj
{
    friend obj* create_obj();

private:
    obj(){}
    obj(const obj&rhs){}
    ~obj()noexcept{}
};

obj* create_obj()   
{
    static obj x;
    return &x;
}

class static

  • 三个成分:
    1、构造私有化
    2、静态成员函数,提供使用的接口
    3、静态变量,唯一的对象
class Printer
 {
    static Printer&  thePrinter();
private:
    static Printer printer;
    Printer(){}
    Printer(const Printer& rhs){}
};

Printer Printer:: printer;
Printer& Printer::thePrinter()
{ return printer; }

class static与function static的优缺点

尽量使用function static

  • class拥有一个static对象即使未使用到它也会被构造,但当function拥有一个static对象意味着此对象在函数第一次被调用时才会产生,
  • static变量在不同编译单元内初始化的顺序是不确定的,因此最好用一个函数包含起来,第一次调用函数时才会对其进行初始化

static与inline最好不要一起搭配

如果你有一个inline的全局函数并其中内含一个局部变量,程序在编译时可能会拥有多份该static对象的副本,违背了声明static只允许一个对象的初衷

控制产生对象的数量

  • 主要方法:内含一个static 数量变量,当外界申请太多对象时在构造函数内抛出一个异常
  • 使用嵌套类,用类名描述异常信息,作为异常
class Printer
{
public:
    class TooManyObjects{};    ⭐
    Printer();
    ~Printer()noexcept;
private:
    static size_t numObjects;
    Printer(const Printer& rhs);
};

size_t Printer::numObjects = 0;
Printer::Printer()
{
    if (numObjects++ >= 1)
    {
        throw TooManyObjects();  ⭐
    }
}

Printer::~Printer() 
{
    --numObjects;
}

不同对象的构造状态

派生对象中的base class成分内嵌于较大对象之中也会涉及对象的构造如果将构造函数私有化,就不能被继承或者内嵌于其他对象内但是有时我们希望实现一个类:1、此类禁止被派生,2、但又不限制对象产生的数量方法:声明伪构造函数

class Obj 
{
public:
    static Obj * makeObj();  ⭐
    static Obj * makeObj(const Obj & rhs);  ⭐
private:
    Obj();
    Obj(const Obj & rhs);
};

Obj * Obj::makeObj()
{
     return new Obj(); 
}

Obj * Obj::makeObj(const Obj & rhs) 
{ 
    return new Obj(rhs);
}

问题:使用new就得delete可以将返回得指针用智能指针对象unique_ptr包含

unique_ptr<Obj> pObj1(Obj::makeObj());
unique_ptr<Obj> pObj2(Obj::makeObj(*pObj1));