Effective c++阅读笔记(不断更新……)

1. copy构造函数和copy赋值的使用区别。

    class A;   

   class B(A);        //调用copy构造函数

   B = A;              //调用copy赋值

   class B = A;   //调用copy构造函数

   如果一个对象被定义,一定会有个构造函数被调用,此时不可能调用赋值操作,如果没有对象定义,就不会调用构造函数,调用的自然是赋值操作。

 copy构造函数定义了如何进行对象的值传递。

2. 尽量以const 、enum、inline代替#define

#define是简单的替换,会导致多份数据的拷贝,而const仅有一份数据拷贝。

3. 类中static静态成员的初始化

方法一: class A {

                       private : static const int Num = 5;            //常量声明(非定义)

                                      int array[Num];         //使用该常量

                     }

           有些编译器可能坚持要看到一个定义式,否则会有编译错误,这时候需要在实现类的cpp文件中(非头文件)中对static成员进行定义,如下:

          const int A::Num;   //因为声明时已经赋予初值,因此此处定义不可以再设初值。如果声明时不设初值,则 array成员不能使用 Num,因为在编译class时,必须要知道array的大小,而此时Num并没有值。

  #define不可以定义这样的常量,因为define并不重视作用域,一旦宏被定义,就会一直有效,除非遇到undef。

方法二: 如果编译器(一般是旧式编译器)不支持static成员在声明时初始化,那可以在定义时初始化,如:

class A {

                       private : static const double  Num ;            //常量声明(非定义)

                             ...

                     }

         const   double  A::Num = 1.89  //同样放在实现文件cpp中,非头文件

方法三:在编译器不支持static成员在类中初始化时,要想在类中使用常量,比如数组大小, 可借助enum

                      class A{

                                 enum { Num = 5};

                               int  array [Num];

                          }

4. 正确使用const

const 出现在 * 左边,表示被指物是常量,出现在 * 右边,表示指针本身是常量, const int * p 与 int const * p是一样的。

const 迭代器 const  vector<T>::iterator it = v.begin()  ,相当于 T * const, 即常量指针,但指向的内容可以变

vector<T>::const_iterator  it = v.begin() 相当于 const T *,指向的内容是常量。

如果要在一个const的成员函数中修改非static成员变量的值,则应以mutable 来修饰要修改的非static成员变量。

5. 如何在non-const成员函数中调用const成员函数?

class  A{

   public :

         const char &   operator[] ( int position )  const  {

                   return text[positon];

           }

         char&  operator[] ( int position ) {

               return     const_cast<char&>( static_cast<const   A&>(*this)[position] );

          }

   .....

}

第二个非const成员函数调用了第一个const成员函数,进行了两次转型。第一次是static_cast  ,他主要是把non-const的(*this)转化为const  A&,这样才能调用到const成员函数。第二个是把返回的const char& 转化成non-const char &。static_cast 类型与C语言中的强制类型转换,如int  a = 10;   double  d = (double) a,; double d = static_cast<double> a.

6. 鼓励在构造函数中使用成员初值列进行成员的初始化,这样比赋值高效。

class A {

     private:

           int  a;

           string  str;

     public:

            A(int d, string  s)  {

                     a = d;

                     str = s;

            }          //这是赋值,并非初始化,先调用string 的default构造函数构造str, 再调用copy构造函数,效率较低

            A (int d, string s) : a(d), str( s) {   };  //这是初始化,直接调用copy构造函数,较高效

}

7. 虚析构函数的使用

在class的继承体系中,如果基类的析构函数为非virtual的,则在释放派生类实例的时候,只能调用基类的析构函数,而派生类本身的没有被调用,造成局部销毁的结果,这这结果是灾难性的。但如果某个类不希望作为基类,则不应该声明virtual析构函数,因为这会增加类的体积,原因是这种类的对象除了类成员变量的空间外,还有些辅助信息用来运行时期确定哪一个virtual函数被调用,通常由一个vptr(virtual table pointer)指针指出,vptr指向一个函数指针数组,称为vtbl(virtual table),每一个带有virtual函数的class都会有一个相应的vbtl。

STL中的vector、list、set、map、string等class都不具有virtual 析构函数,所以最好不要用作基类。

带多态性质的基类应该声明一个virtual析构函数,如果class带有任何virtual函数,他就应该有一个virtual析构函数;如果class设计的目的不是作为基类,或不是为了具备多态性,就不该声明virtual析构函数。

 8. 不要让异常逃离析构函数

如果一个析构函数可能会抛出异常,要用try。。catch捕捉,防止异常传播,产生程序过早结束或者不明确的行为。如果程序员自己希望处理这种异常,则需要单独写一个成员函数捕捉异常,在析构函数中无法处理。

 

9. 将文件间的编译依存关系降至最低:

如果一个class中需要引用到别的class或者struct,不要include包含这些class或struct的头文件,而应在定义的class前直接声明这些class和struct,如:

class Date;

class Address;

class Persion

{

    private :

            Date date;

            Address  add;

....

};

 

10: private 的virtual函数允许子类重定义,但是不能调用,如果要调用,一个方法是在基类写个非virtual函数,里面直接调用private的virtual函数,这样调用非virtual的函数时

动态确定里面调用的是那个子类的virtual函数。

11. 在private继承中,子类不能转换为基类,即不能让一个声明为基类的指针指向某一个子类!因为private继承并不是is-a关系

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1 目标检测的定义 目标检测(Object Detection)的任务是找出图像中所有感兴趣的目标(物体),确定它们的别和位置,是计算机视觉领域的核心问题之一。由于各物体有不同的外观、形状和姿态,加上成像时光照、遮挡等因素的干扰,目标检测一直是计算机视觉领域最具有挑战性的问题。 目标检测任务可分为两个关键的子任务,目标定位和目标分。首先检测图像中目标的位置(目标定位),然后给出每个目标的具体别(目标分)。输出结果是一个边界框(称为Bounding-box,一般形式为(x1,y1,x2,y2),表示框的左上角坐标和右下角坐标),一个置信度分数(Confidence Score),表示边界框中是否包含检测对象的概率和各个别的概率(首先得到别概率,经过Softmax可得到别标签)。 1.1 Two stage方法 目前主流的基于深度学习的目标检测算法主要分为两:Two stage和One stage。Two stage方法将目标检测过程分为两个阶段。第一个阶段是 Region Proposal 生成阶段,主要用于生成潜在的目标候选框(Bounding-box proposals)。这个阶段通常使用卷积神经网络(CNN)从输入图像中提取特征,然后通过一些技巧(如选择性搜索)来生成候选框。第二个阶段是分和位置精修阶段,将第一个阶段生成的候选框输入到另一个 CNN 中进行分,并根据分结果对候选框的位置进行微调。Two stage 方法的优点是准确度较高,缺点是速度相对较慢。 常见Tow stage目标检测算法有:R-CNN系列、SPPNet等。 1.2 One stage方法 One stage方法直接利用模型提取特征值,并利用这些特征值进行目标的分和定位,不需要生成Region Proposal。这种方法的优点是速度快,因为省略了Region Proposal生成的过程。One stage方法的缺点是准确度相对较低,因为它没有对潜在的目标进行预先筛选。 常见的One stage目标检测算法有:YOLO系列、SSD系列和RetinaNet等。 2 常见名词解释 2.1 NMS(Non-Maximum Suppression) 目标检测模型一般会给出目标的多个预测边界框,对成百上千的预测边界框都进行调整肯定是不可行的,需要对这些结果先进行一个大体的挑选。NMS称为非极大值抑制,作用是从众多预测边界框中挑选出最具代表性的结果,这样可以加快算法效率,其主要流程如下: 设定一个置信度分数阈值,将置信度分数小于阈值的直接过滤掉 将剩下框的置信度分数从大到小排序,选中值最大的框 遍历其余的框,如果和当前框的重叠面积(IOU)大于设定的阈值(一般为0.7),就将框删除(超过设定阈值,认为两个框的里面的物体属于同一个别) 从未处理的框中继续选一个置信度分数最大的,重复上述过程,直至所有框处理完毕 2.2 IoU(Intersection over Union) 定义了两个边界框的重叠度,当预测边界框和真实边界框差异很小时,或重叠度很大时,表示模型产生的预测边界框很准确。边界框A、B的IOU计算公式为: 2.3 mAP(mean Average Precision) mAP即均值平均精度,是评估目标检测模型效果的最重要指标,这个值介于0到1之间,且越大越好。mAP是AP(Average Precision)的平均值,那么首先需要了解AP的概念。想要了解AP的概念,还要首先了解目标检测中Precision和Recall的概念。 首先我们设置置信度阈值(Confidence Threshold)和IoU阈值(一般设置为0.5,也会衡量0.75以及0.9的mAP值): 当一个预测边界框被认为是True Positive(TP)时,需要同时满足下面三个条件: Confidence Score > Confidence Threshold 预测别匹配真实值(Ground truth)的别 预测边界框的IoU大于设定的IoU阈值 不满足条件2或条件3,则认为是False Positive(FP)。当对应同一个真值有多个预测结果时,只有最高置信度分数的预测结果被认为是True Positive,其余被认为是False Positive。 Precision和Recall的概念如下图所示: Precision表示TP与预测边界框数量的比值 Recall表示TP与真实边界框数量的比值 改变不同的置信度阈值,可以获得多组Precision和Recall,Recall放X轴,Precision放Y轴,可以画出一个Precision-Recall曲线,简称P-R
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值