Brief Notes of 《Effective C++》

2021-01-27  本文已影响0人  老杜振熙

本文为学习《Effective C++》各个条款之后的一点概要式的总结。
github博客地址

条款2 尽量以const, enum, inline替代#define

条款3 尽可能使用const

条款5 了解C++默认编写并调用哪些函数

条款7 为多态基类声明virtual析构函数

条款8 别让异常逃离析构函数

条款11 在operator=中处理“自我赋值”

核心其实就是不能让指针指向一个未获取的资源;存在3类方法,各有各的优势

条款12 复制对象是勿忘其每一个成分

条款14 在资源管理类中小心copying行为

对RAII对象执行复制,是需要万分小心的行为,因为它涉及到的资源的最佳处理方式不甚相同;常见的方式包括:

条款15 在资源管理类中提供对原始资源的访问

条款16 以独立语句将newed对象置入智能指针

条款19 设计class犹如设计type

不多说了,在编写类代码的时候多看看本条款,思考条款中列出的问题;

条款23 宁以non-member、non-friend替换member 函数

条款24 若所有参数皆需要类型转换,请为此采用non-member函数

条款26 尽可能延后变量定义式的出现时间

// 第一种
{
  ...
  Weight tmp;
  for(int i = 0; i < N; ++i){
    tmp = Weight(i);
  }
}
// 第二种
{
  for(int i = 0; i < N; ++i){
    Weight tmp= Weight(i);
    ...
  }
}

条款29 为“异常安全”而努力是值得的

条款30 透彻了解inlining的里里外外

条款31 将文件间的编译依存关系降至最低

C++中降低文件间的编译依赖,主要就是两种手段:handle class以及interface class

条款33 避免遮掩继承而来的名称

class Base{
public:
    // 重载函数
    void f(int);
    void f();

};

class Derived : public Base {
public:
    using Base::f; // OK,基类的重载函数不会被覆盖了
    void f(int, int);
};

条款34 区分接口继承和实现继承

条款37 绝不重新定义继承而来的缺省参数值

条款38 通过复合塑膜出has-a或“根据某物实现”

条款39 明智而审慎地使用private继承

条款40 明智而审慎地使用多重继承

条款41 了解隐式接口和编译器多态

条款42 了解typename的双重意义

条款43 学习处理模板化基类的名称

条款44 将与参数无关的代码抽离templates

条款45 运用成员函数模板接受所有兼容类型

比如对于如下的一个模板类,很多时候,我们可能需要使用TmpDemo<int>去初始化一个tmpDemo<double>对象。这完全是合理的,但问题是,在模板编程的世界里,TmpDemo<int>TmpDemo<double>是完全没有任何关系的。或者可以直接在模板类中定义这样一个构造函数,但如果遭遇了其他的需求呢?比如说int变为了char,又或者,现在的typename是一个继承谱系中的各种类型。显然,单一的成员函数是解决不了问题的。

template <typename T>
class TmpDemo{
  // ...
};

条款46 需要类型转换时请为模板定义非成员函数

template <typename T>
class TmpDemo{
public:
  TmpDemo(const T& num){value = num;}
private:
  T num;
};

template <typename T>
const T addFunc(const TmpDemo<T> &t1, const TmpDemo<T> &t2){
  return t1.num * t2.num;
}

TmpDemo<int> tmp(2);

条款49 了解new-handler的行为

class HandleHolder{
public:
    HandleHolder(const HandleHoldr &) = delete; // 禁止拷贝
    HandleHolder &operator=(const HandleHolder &) = delete;

    HandleHolder(std::new_handler p): oldHandler(p) {}
    ~HandleHolder(){std::set_new_handler(oldHandler);}
private:
    std::new_handler oldHandler;
};

template <typename T>
class NewHandlerHelper{ // 此处没有定义自己的set_new_handler了,感觉没有必要
public:
    NewhandlerHelper(std::new_handler p): myHandler(p) {}
    static void *operator new(size_t size) throw(std::bad_alloc){ // 每个class对应一个operator new
        HandleHolder tmp(std::set_new_handler(myHandler)); // std::set_new_handler会返回之前的new-handler
        return ::operator new(size);
        // tmp被析构,new-handler也就得以恢复
    }

private:
    static std::new_handler myHandler; // 每个class对应一个new_handler
};

template <typename T>
std::new_handler NewHandlerHelper<T>::myHandler = nullptr; // static变量要记得初始化

class Widget : public NewHandlerHelper<Widget> { // 自己继承自己,虽然看起来很奇怪,但实际上是行得通的;本质上只是让不同的class拥有不同的myHandler
    /**
     * ...
     * Widge只要在构造函数处给NewHandlerHelper提供自己的new-handler即可
     * ...
     */
};

条款52 写了placement new也要写placement delete

上一篇下一篇

猜你喜欢

热点阅读