1ms Faster
Home
  • Program

    • Lean in C++
  • Perfromance Engineering

    • [>>>>>]
  • Reading Note

    • [>>>>>]
  • ComputeArch

    • [_]
  • Compiler

    • [_]
  • System

    • [_]
Authoring
  • Categories
  • Tags
GitHub (opens new window)

Quincy Jet

We are.
Home
  • Program

    • Lean in C++
  • Perfromance Engineering

    • [>>>>>]
  • Reading Note

    • [>>>>>]
  • ComputeArch

    • [_]
  • Compiler

    • [_]
  • System

    • [_]
Authoring
  • Categories
  • Tags
GitHub (opens new window)
  • Lean in c++

  • Performance Engineering

  • Misc

  • Reading Notes

    • Effective C++

    • More Effective C++

      • 基础议题
      • 操作符(operators)
      • 异常(exceptions)
      • 效率(efficiency)
      • 技术(techniques, idioms, patterns)
        • 技术(techniques, idioms, patterns)
          • Item 25:将 constructor和 non-member functions虚化
          • Item 26:限制某个 class所能产生的对象数量
          • Item 27:要求(或禁止)对象产生于 heap之中
          • Item 28:Smart Pointers(智能指针)
          • Item 29:Reference counting(引用计数)
          • Item 30:为什么要使用Proxy classes(替身类、代理类)
          • Item 31:如何让函数根据一个以上的对象类型来决定如何虚化
      • 杂项讨论,Misc
    • 《C++ 性能优化指南》
  • Wiki
  • Reading Notes
  • More Effective C++
Quincy Jet
2022-06-27
Content

技术(techniques, idioms, patterns)

#

# 技术(techniques, idioms, patterns)

这部分内容更像是设计模式要解决的相关的问题;

# Item 25:将 constructor和 non-member functions虚化

virtual copy constructor 感觉和设计模式里面的工厂模式是差不多的概念

non-member function的虚化:写一个虚函数做实际工作,再写一个什么都不做的非虚函数,只负责调用虚函数。当然啦,为了避免这种操作受到函数调用所带来的成本,你可以将非虚函数 inline

#include <iostream>

class A
{
    public:
        virtual std::ostream &print(std::ostream &s) const = 0;
};

class B: public A
{
    public:
        virtual std::ostream &print(std::ostream &s) const { s << "i am b"; return s; };
};

class C : public A
{
    public:
        virtual std::ostream &print(std::ostream &s) const { s << "i am c"; return s; };
};

std::ostream &operator <<(std::ostream &s, const A &a) // 这就是那个非虚函数,负责调用上面的虚函数
{
    return a.print(s);
}

int main(void)
{
    B b;
    C c;
    std::cout << b << "\n" << c << std::endl;

    return 0;
}	
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

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

限制某个class所能产生的对象数量(如果只是一个, 那么用static对象, 记得看singleton设计模式)

使用引用计数

使用全局函数, 并且用private来封锁ctor和dtor,全局函数里面包裹一个static的对象, 只能产生一个:

class Printer{
public:
	void submitJob(const PrintJob& Job);
    void reset();
   	void performSelfTest();
    friend Printer& thePrinter();
    ...
private:
    Printer();
    Printer(const Printer& rhs);
    ...
}

Printer& thePrinter(){
    static Printer p; // 这里限制了程序只能产生一个P
    return p;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

但是全局函数是不安全的, 最好不要动不动就用全局的东西

使用namespace来包裹一下这个全局函数, 会在使用的收, 增加对全局函数作用域的控制;

“class拥有一个 static对象”的意思是:即使从未被用到,它也会被构造(及析构)。相反地“函数拥有一个 static 对象”的意思是:此对象在函数第一次被调用时才产生。如果该函数从未被调用,这个对象也就绝不会诞生(然而你必须付出代价,在函数每次被调用时检查对象是否需要诞生)

# Item 27:要求(或禁止)对象产生于 heap之中

手动限制或者禁止对象产生与heap之中, 把ctor和dtor, operator new(), operator new放在private里面,或者使用=delete

(private不能继承, 但是可以弄成protected的,但是弄成protected就不知道是在heap上还是stack上面了)

class A
{
public:
    /* 做一个伪析构 */
    void destory() { this->~A(); }

private:
    /* 析构函数设为私有,防止在栈上构建对象 */
    ~A() { };
};

class M
{
    // A a_; /* 错误,不可在堆上创建 */
    A *pa_; /* 在内含类中,需要改为指针使用 */
};

int main(void)
{
    // A a; /* 错误 */
    A *pa = new A(); /* 正确 */
    // delete pa; /* 错误 */
    pa->destory(); /* 正确 */

    return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

禁止在heap上产生对象, 要把operator new(), operator new以及相应的delete函数放在private里面;

#include <iostream>

class A
{
public:
    /* 用c++11的方式 */
    /*
        static void *operator new(size_t) = delete;
        static void operator delete(void *) = delete;
        static void *operator new [](size_t) = delete;
        static void operator delete [](void *) =delete;
    */
private:
    static void *operator new(size_t);
    static void operator delete(void *);
    static void *operator new [](size_t);
    static void operator delete [](void *);
};

int main(void)
{
    A a;
    // A *pa = new A();   /* 错误 */
    // A *pa = new A[10]; /* 错误 */
    A *p = &a;
    // delete p; /* 错误,delete已经被私有化,编译器就可以报错,delete []同原理 */

    return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

# Item 28:Smart Pointers(智能指针)

smart pointer智能指针,在现代C++里面, 主要是auto_ptr(), shared_ptr()相关的类型, 可以使用;

# Item 29:Reference counting(引用计数)

reference counter引用技术 、 copy on write相关的技术

(如何实现引用计数?)

# Item 30:为什么要使用Proxy classes(替身类、代理类)

代理类实际上有三种好处,

  • 实现多维数组: 真实数组为一个一维数组,内嵌代理为一个一维数组,组合起来就是一个二维数组
  • 区分读写
  • 压制隐式转换 因为返回的类型为代理类类型,所以很多操作需要隐式类型转换,如果代理类没实现,就不能进行隐式类型转换,这样可以有效的压制隐式类型转换

# Item 31:如何让函数根据一个以上的对象类型来决定如何虚化

让函数根据一个以上的对象类型来决定如何虚化这个函数;

虚函数的调用其实也可以理解为一个message dispatch, 如果一个虚函数要根据两个参数的类型来进行虚化, 则称为 double dispatch,

使用RTTI, typeid();

​

效率(efficiency)
杂项讨论,Misc

← 效率(efficiency) 杂项讨论,Misc→

Copyright © 2017-2023 Quincy Jet | MIT License
  • Auto
  • Light
  • Dark
  • Read