Effective C++ 读书笔记(一)

Effective C++ 读书笔记(一):让自己习惯 C++ 条款01:视 C++ 为一个语言联邦 C Object-Oriented C++ Template C++ STL 条款02:尽量以const,enum,inline替换 #define 对于单纯常量,最好以 const 对象或 enums 替换 #defines 对于形似函数的宏(macros),最好改用 inline 函数替换 #defines 条款03:尽可能使用 const 将某些东西声明为 const 可帮助编译器侦测出错误用法。const 可被施加于任何作用域内的对象、函数参数、函数 阅读详情
1.C++ 高效编程守则视状况而变化,取决于你使用C++的哪一部分
       C++主要包括:C、Object-Oriented C ++、Template C++以及STL 

2.对于单纯常量,最好以const对象或enums替换  #define
   对于形似函数的宏,最好改用inline函数替代    #define

#include <iostream>
using namespace std;
#define CALL_WITH_MAX(a,b) f((a)>(b)?(a):(b))

void f(int x)
{
    //cout << x << endl;
}

inline void callWithMax(const int &a,const int &b)
{
    f(a>b?a:b);
}

class GamePlayer
{
public:
    static const int NumTurns = 5;  //常量表达式
    enum {NumTurns01 = 5};
    int scores[NumTurns];
    char str[NumTurns01];
};

3.令某些东西声明为const可帮助编译器侦测出错误用法。用const可被施加于任何作用域内的对象、函数参数、函数返回类型、成员函数本体。

 解释:const 出现在星号左边,表示所指物是常量;如果出现在星号右边,表示指针自身是常量;
              const int *p 和 int const *p表达的意思是一样的。
     
            声明迭代器为const就像声明指针为const一样(T*const指针),表示迭代器不得指向不同的东西,但它所值的东西是可以改动的。如果你希望迭代器所指向的东西不可以被改动,你需要使用const_iterator。

     const成员函数:
         a. 它们使class接口比较容易被理解,这是因为,得知哪个函数可以被改动对象内容而哪个函数不行,很是重要的。
         b. 它们使“操作const对象”成为可能。
      注意:两个成员函数如果只是常量性不同,可以被重载。

   编译器强制实施bitwise constness, 但你编写程序时应该使用“概念上的常量性”。
   解释:当const和none-const成员函数有着实质等价的实现时,令non-const版本调用const版本可避免重复。如果在const函数内部调用non-const函数,是错误的:因为对象有可能因此被改动,但反向调用是安全的,non-const成员函数本来就是对其对象做任何动作,所以在其中调用一个const成员函数并不会带来风险。

       bitwise constnes(物理常量):成员函数只有在不更改对象之任何成员变量时才可以说是const,也就是说不更改对象内的任何一个bit。
       概念常量:一个const成员函数可以修改它所处理的对象内的某些bit.
       可以使用mutable释放non-static成员变量的bitwise constness约束。
 当const和非const成员函数有着实质等价的实现时,令non-const版本调用const版本可避免代码重复。
class TextBlock
{
public:
    TextBlock(string aStr=""):text(aStr){}
    const char& operator[](size_t postion) const {cout <<"const const version."; return text[postion];}
    char& operator[](size_t position)  {cout << "none version.";return text[position];}
    size_t getLength() const {length = 10; return length;}
private:
    string text;
    mutable size_t length;
    mutable bool isValid;
}
char& TextBlock::operator[](size_t position)
{
    return const_cast<char &>(static_cast<const TextBlock>(*this)[position]);
}        

4. 为内置类型对象进行手动初始化,因为C++不保证初始化它们。
    构造函数最好使用成员初始化列表,而不是在构造函数本体内使用赋值操作。初始化列表列出的成员变量,其次序应该和它们在class 中的声明次序相同
    为免除“跨编译单元之间初始化次序”问题,请以local static对象替换non-local static对象。

5.编译器可以暗自为class 创建default构造函数、拷贝构造函数、赋值运算符重载函数以及析构函数,且这些函数的都是public的且inline。
    注意:无论是编译器生成的,或用户自定义的析构函数都会自动调用其non-static成员变量的析构函数。
       默认构造函数和析构函数主要是给编译器一个地方用来放置“藏身幕后”的代码,像是调用base classes和non-static成员变量的析构函数和构造函数。
      注意:
       1.编译器产生的析构函数是一个non-virtual,除非这个class的base class 自身声明有virtual析构函数。
       2.如果某个基类将赋值运算符重载函数声明为private,编译器将拒绝为其派生类生成一个赋值运算符重载函数。毕竟编译器为派生类所生成的赋值运算符函数想象中可以处理基类的成分,但它们当然无法调用派生类的成员无权调用的成员函数。编译器两手一摊,无能为力。此时编译器拒绝赋值动作。
       3. 如果在一个“内含reference成员或const成员”的class内支持赋值操作,你必须自己定义赋值运算符重载函数。
     #include <iostream>
     #include <string>
     using namespace std;

     template<typename T>
     class NamedObject
     {
           template<typename T> friend ostream& operator<<(ostream& os,const      NamedObject<T> &object);
     public:
                NamedObject(string& name, const T& value);
                NamedObject& operator=(const NamedObject& object);
                void SetNameValue(string& name) {nameValue = name;}
     private:
               string&  nameValue;
               const T  objectValue;
     };

     template<typename T>
     NamedObject<T>::NamedObject(string& name, const T&      value):nameValue(name),objectValue(value)
     {
     }
     template <typename T>
     ostream& operator<<(ostream& os, const NamedObject<T> &object)
     {
               os << "name:" << object.nameValue << "   value:" << object.objectValue << endl;
                return os;
     }
     template<typename T>
     NamedObject<T>& NamedObject<T>:: operator=(const NamedObject<T>& object)
     {
                 if (this == &object)
                          return *this ;

                 this->nameValue = object.nameValue;

                 return *this ;
     }
     int main(int argc,char **argv)
     {
                //string s("hello");
                //string &p = s;
                //p = "world";
                //cout << s << endl;
   
               string p = "p";
               string s = "s";
                //string& p2 = p;
                //string& s2 = s;
                //p2 = s2;
   
               NamedObject < int>  p1(p,1);
               p1.SetNameValue(s);
               cout << p1;   //s
               cout << p<< endl;;     //s

               NamedObject< int>  s1(s,2);
                //p1 = s1;  //error C2582: “operator =”函数在“NamedObject<T>”中不可用
               s = "p";
               p1 = s1;
               cout << p1; //p
               cout << endl;
               return 0;
     }

6.为驳回编译器自动(暗自)提供的功能,可将相应的成员函数声明为private并且不予实现。不过这种方法并不绝对安全,因为member函数和friend函数还是可以调用你的private函数。
使用像Uncopyable这样的base class也是一种方法。
例如:
 class Uncopyable
{
protected:
    Uncopyable(){}
    ~Uncopyable(){}
private:
    Uncopyable(const Uncopyable&);
    Uncopyable& operator=(const Uncopyable&);
};
class MyClass: private Uncopyable
{  
};
int main(int argc, const char * argv[])
{   
    MyClass obj01;
    MyClass obj02(obj01);  //Error
    obj01 = obj02;         //Error
}

     当尝试拷贝MyClass对象时候,编译器便试着生成一个拷贝构造函数和一个赋值运算符重载函数,这些函数的“编译器生成版本”会尝试调用其base class的对应的兄弟,那些调用会被编译器拒绝,因为其base class的拷贝构造函数是private。

7.带多态性质的base classes应该声明一个virtual析构函数。如果class带有任何virtual函数,它就应该拥有一个virtual析构函数。
       Classes的设计目的如果不是作为base classes使用,或不是为了具备多态性,就不应该声明为virutal析构函数。
      当derived class对象经由一个base class指针被删除,而该base class带着一个non-virtual析构函数,其结果未有定义---实际执行时通常发生的是对象的derived成分没被销毁。
       注:1.所有STL容器不带virtual析构函数。
              2.可以将一个类的析构函数声明为纯析构函数,但是你必须为其提供一份定义。
8.析构函数绝对不能吐出异常。如果一个被析构函数调用的函数可能抛出异常,析构函数应该捕捉任何异常,然后吞下它们(不传播)或结束程序。
    如果客户需要对某个操作函数运行期间抛出的异常做出反应,那么class应该提供一个普通函数(而非在析构函数中)执行该操作。
     如果某个操作在失败时抛出异常,而又存在某种需要必须处理该异常,那么这个异常必须来自析构函数以为的某个函数。如果析构函数吐出异常就是危险,总会带来“过早结束程序”或“发生不明确行为”的风险。
9.在构造函数和析构函数内不要调用virtual函数,因为这类调用从不下降至derived class(比起当前执行构造函数和析构函数的那层)。
10.令赋值操作符返回一个reference to *this.
11.确保当对象自我赋值时operator=有良好的行为。其中技术包括比较“来源对象”和“目标对象”的地址,精心周到的语句顺序以及copy and swap.
/*
 
考虑异常安全性的解法(Exception Safety)原则
 */

CMyString& CMyString::operator=(const CMyString &str)
{
   if (this != &str)
   {
       CMyString strTemp(str);
      
       char *PTemp = strTemp.m_pData;
       strTemp.m_pData  = m_pData;
       m_pData = PTemp;
   }
    return *this;
}
  确定任何函数如果操作一个以上的对象,而其中多个对象是同一个对象时,其行为仍正确。
12.拷贝构造函数应该确保复制“对象内所有成员变量”以及“所有base class”成分。
   不要尝试以某个拷贝函数实现另一个构造函数。应该将共同的机能放进第三方函数中,并由拷贝函数共同调用。

   #include <iostream>
    #include <string>
    using namespace std;

     class Derived;
     class Base
     {
           friend ostream& operator <<(ostream& os,const Base& object);
           friend ostream& operator <<(ostream&os,const Derived& object);
     public:
          Base( int _id=10):id(_id) {}
           //Base& operator=(const Base& ojb) { cout << "called base::operator=" << endl; return *this;}
     private:
           int id;
     };
     ostream& operator<<(ostream& os, const Base& object)
     {
               os << object.id << endl;
                return os;
     }
     class Derived : public Base
     {
                friend ostream& operator <<(ostream&os,const Derived& object);
     public:
          Derived(string _name= "",int _id=0):Base(_id),name(_name){}
          Derived& operator=(const Derived& obj)
          {
                   cout << "Derived::operator= called" << endl;
                    this->name = obj.name;
                   Base:: operator=(obj);
                    return *this ;
          }
     private:
          string name;
     };
     ostream& operator<<(ostream&os, const Derived& object)
     {
            os << object.id << "   " << object.name << endl;
            return os;
     }
     int main(int argc,char**argv)
     {
          Base base(10);
          cout << base ;


          Derived derived01( "hello",12);
          Derived derived02( "world",13);
  
           //调用复制运算符重载函数,它会自动调用基类的复制运算符函数
          derived01 = derived02; 
          cout << derived01;   //13 world
         cout << derived02;   // 13 world


           return 0;
     }
     c++默认提供的的复制运算符函数会自动的调用基类的赋值运算符函数,当重载了派生类的赋值运算符函数时候,需手动完成对基类赋值运算符函数的调用。

13.为防止资源泄漏,请使用RAII对象,它们在构造函数中获得资源并在析构函数中释放资源。
   两个经常被使用的RAII classes分别为tr1::shared_ptr和auto_ptr.前者通常是较佳选择,因为其copy行为比较直观。若选择auto_ptr,复制动作会使它(被复制物体)指向null.

14.复制RAII对象必须一并复制它所管理的资源,所以资源的copying行为决定RAII对象的copying行为。
   普通常见的RAII class copying行为是:抑制coping、施行引用技术法。不过其他行为也都可能被实现。

15.APIs往往要求访问原始资源,所有每一个RAII class应该提供一个“取得其所管理之资源”的方法。
   对原始资源的访问可能经由显式转换或隐士转换。一半而言显式转换比较安全,但隐式转换对客户比较方便。

16.如果你在new表达式中使用[],必须在相应的delete表达式中使用[].如果你在new表达式中不是用[],一定不要在相应的delete表达式中使用[].
   最好尽量不要对数据形式做typedef动作

17.以独立语句将newed对象存储于(置于)智能指针内。如果不这样做,一旦异常抛出,有可能导致难以察觉的资源泄漏。


磁带库Scalar i6000界面基本操作步骤 (注:磁带库的前面的门不要打开,日常维护:主要就是简单看下磁带库的状态;绿色代表正常;黄色代表报警但不影响磁带库正常使用;红色代表报警,不能正常使用,及时和厂家联系报修。) 一、磁带库管理页面 1、首先,磁带库前面(具体作用如图) 2、查看状态和管理页面 3、管理页面登陆。用户名:service 密码:xxxxxx 4、磁带机背面 二、电脑连接磁带库进入管理页面 1.用网线把电脑和磁带库的维护接口(磁带库背面)进行连接 2.电脑环境:JAVA。把电脑的IP设置成自... 阅读详情

相关推荐

智能体评测技术与实践:从评估维度到DeepEval实战指南

智能体评测技术与实践:从评估维度到DeepEval实战指南 本文系统探讨了AI智能体的评测体系与实践方法。首先从四个关键维度构建评估框架:基础能力(意图理解、知识完整性)、复杂任务(多轮对话、动态工作流)、可靠性(幻觉抑制、安全合规)以及工具效率(参数填充、多工具协同)。其次分析了主流评测工具,包括xBench的动态双轨评估、DeepEval的全链路监控等解决方案。最后详细介绍了DeepEval的实战应用,涵盖环境配置、测试用例构建、指标配置及CI/CD集成,展示了如何通过代码化评估实现智能体质量的持续提升

Linda的自动化测试之旅 3416

【C++】《Effective C++》读书笔记汇总

我之前边读《Effective C++》边写下每个条款的读书笔记,这一版是C++11之前的版本。这里我将每个条款令我印象深刻的点小结一下。 1、C++包括:Plain C(面向过程)、OOP(面向对象)、模板(泛型和模板元编程)、STL(C++标准库)。 2、用inline、enum、const代替#define。#define定义的宏,一旦复杂起来,高手都很难掌控。不要带入C的习惯。

artzers的专栏 6065

2025东三省D题深圳杯数学建模实战解析:基于多模型融合的法医STR混合样本智能识别系统

本文深入解析了2025年东三省数学建模竞赛D题,即深圳杯赛题,聚焦于法医STR混合样本的智能识别挑战。文章系统阐述了构建一个基于多模型融合的智能识别系统的完整流程,涵盖贡献者人数判定、DNA贡献比例估计、个体基因型推断以及STR谱图去噪四大核心步骤。通过融合高斯混合模型、随机森林、非负矩阵分解、小波变换与深度学习等多种技术,并强调特征工程的重要性,为破解法医DNA混合样本分析这一行业难题提供了清晰的数学建模与AI实战思路。

weixin_29050271的博客 392

Effective C++读书笔记

第0章       导读 1.      Size_t只是typedef,是C++计算个数(例如char*-based字符串内的字符个数或STL容器内的元素个数等等)时用的某种不带正负号(unsigned)类型。它也是vector,deque和string内的operator[]函数接受的参数类型。 第1章       让自己习惯C++ 条款01:视C++为一个语言联邦 1.      今

Chris.Xiao 854

一起玩转GNU Radio:调制解调大合集

本文汇总了GNU Radio中多种常见的调制解调方法及其参考文献链接,便于今后查看,供大家参考!

无线通信实验室 1万+

ROS教程(四):RVIZ使用教程(详细图文)

前言 根据前面的教程已经学会了创建功能包,那么本篇文章主要内容则是通过节点来发布数据至RVIZ

Leslie的博客 17万+

《Effective C++》读书笔记

一、让自己习惯C++ 1、视C++为一个语言联邦 1、对内置对象类型而言,pass_by_value比pass_by_reference更高效。对用户自定义对象类型而言,pass-by-reference-to-const往往更好。 2、尽量以const、enum、inline替换#define 3、尽可能使用const 1、如果const出现在星号左边,表示被指物是常量,如果const...

聆听风雨的博客 1613

ControlRig蓝图节点对应代码(自用)

用于通过python生成ControlRig蓝图节点,非完整

dicha9的博客 426

Effective C++(读书笔记)

Effective C++ 这本书共有九个章节55条建议,目录如下: 一. 让自己习惯C++       01.视C++为一个语言联邦       02.尽量以const, enum, inline, 替换#define       03.尽可能使用const       04.确定对象被使用前已被初始化 二. 构造/析构/赋值运算       05.了解C++默认编写并调用哪些函数...

前路漫漫的博客 490

接入 AI 之后,为什么测试和排障还是没有真正变快?

如果你们准备做平台型 AI,不要先从聊天入口开始想。先把真实数据采上来;再把链路、版本、快照、报告这些核心对象建稳;再把历史沉淀、反馈、检索能力补齐;最后再让 AI 围绕这些对象去工作。这样做出来的 AI,才更容易从“看起来聪明”走向“真正省时间”。

专注 AI 精准测试平台实战落地,分享从代码 Diff 到回归决策的完整工程闭环。主张“先建数据链路,再上 AI 智能”,让测试从“靠经验”走向“基于风险”。 527

EMB电子机械制动执行器五大核心部件选型解析

本文介绍了EMB电子机械制动执行器五大核心部件的选型方案:采用无刷直流电机作为驱动源,兼具高扭矩和快速响应特性;选用滚珠丝杠传动机构,实现高效旋转-直线转换;行星齿轮减速器满足紧凑空间内的增扭需求;QT450-QT550材质的钳体确保刚度要求;应变片式压力传感器实现夹紧力精确测量。各部件选型综合考虑了性能、可靠性和空间限制,为EMB系统设计提供了完整解决方案。

m0_59012156的博客 1737

《Effective C++》阅读笔记

《Effective C++》阅读笔记 第一章:让自己习惯C++ 1、视C++为一个语言联邦 a、C++由四个部分组成: C、Object-Oriented C++、Template C++、 STL。 b、每一个部分有自己独立的高效编程守则 2、用cons...

weixin_30883311的博客 131

[QMT量化交易小白入门]-七十三、主力资金动向:板块与个股资金流数据API(量化python代码解析)

本专栏主要是介绍QMT的基础用法,常见函数,写策略的方法,也会分享一些量化交易的思路,大概会写100篇左右。QMT的相关资料较少,在使用过程中不断的摸索,遇到了一些问题,记录下来和大家一起沟通,共同进步。

木头大左的博客 1117

Effective C++ | 读书笔记 (一)

这意味着,如果你在一个编译单元中依赖于另一个编译单元中的全局静态对象的初始化结果,你的程序可能会遇到未定义行为,因为那些对象的初始化次序是不确定的。在构造、析构函数中一定只会调用本类中的虚函数。原因:当基类指针(引用)指向子类对象时,如果析构对象通过delete 指针的方式,只会调用基类的析构函数,不会调用子类的析构函数。如果把这个当做是基类,会有问题,析构函数只有声明没有定义,析构函数从派生类到基类的调用时,会发生链接错误。时,先调用基类的构造函数,此时派生类还没有被构造出来,所以调用的是基类的虚函数。

m0_74795952的博客 1042

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

《Effective C++》读书笔记(一)

《Effective C++》读书笔记 条款01:视C++为一个语言联邦 C++高效编程守则视状况而变化,取决于你使用C++的哪一部分(C, Obejct-Oriented C++, Template C++, STL)。 条款02:尽量以const, enum, inline替换#define 对于单纯常量,最好以const对象或enum替换#define。 对于形似函数的宏,最好改用inline函数代替#define。 条款03:尽可能使用const 将某些东西声明为const可帮助

WINGREZ‘S BLOG 618

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

Effective C++ 读书笔记一

2018.3.27 几点说明 从C转向C++ 内存管理 2018.3.28 哎,竟然看的第二版,也是醉了,重新看!! 正文之前 让自己习惯C++ Item 1: View C++ as a federation of languages. Item 2: Prefer consts, enums, and inlines to #defines. Item 3: Use const when...

月寒日暖的博客 274

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

Effective C++ 读书笔记(一)

Effective C++ 读书笔记(一) 1、让自己习惯C++ 条款 01 :视C++为一个语言联邦 C++的四个层次: C:C++是在C语言的基础上发展而来的 Object-Oriented C++:这是C++中不同于C的部分,这里主要指面向对象。 Template C++:C++中的泛型编程。 STL:这是一个标准模板库,它用模板实现了很多容器、迭代器和算法,使用STL往往事半功倍。 条...

qq_40028201的博客 1011

effective c++读书笔记(一)

effective c++读书笔记

qq_31065851的博客 633

Effective C++读书笔记(一)

一、让自己习惯C++    条款01:视C++为一个语言联邦    将C++视为一个由相关语言组成的联邦而非单一语言,由四个主要的次语言组成。 C。说到底C++仍是以C为基础。区块,语句,预处理器,内置数据类型,数组,指针统统来自C。 Object-Oreinted C++。这一部分也就是C with Classes所诉求的。类,封装,继承,多态,virtual函数(动

u010358881的专栏 387

《Effective C++》读书笔记一

1、C++中std是什么意思? 摘自:https://blog.youkuaiyun.com/calvin_zhou/article/details/78440145 在程序中像vector ,cout,这类东西都是在std内,有时会忽略std::,你得自己认清 2、 3、尽量以Const、enum、inline替换#define 举例:定义常量可以用define方式 ...

zhangxiaofan666的博客 533

《More Effective C++》读书笔记一

1、关于指针和引用简单点说就是引用不可能为空,如果你在类成员中定义了引用,则必须在构造函数基/成员初始值设定项列表中初始化就是这种形式 A():ref(b) 这种形式初始化引用没法在使用过程中更改指向对象,引用也永远不可能为空,所以你不需要像指针那样用之前都小心翼翼的判定是否为NULL但同样这样灵活性就下降了其实我个人还是主张完全不用引用的,QT的设计者就说过,函数参数采用指针的更容易让调用者明白此函数可能会改写某参数的值得加上&求地址,而引用方式调用却和普通函数一样,想知道函数是否会对参数内容修改得看函数

瓶子的笔记本 1017

effective C++读书笔记(一)

1. 让自己习惯C++(Accustoming yourselfto C++) 条款01: 视C++ 为一个语言联邦(ViewC++ as a federation of languages) C++已经不是单一的语言,而是一个由相关语言组成的联邦。它由若干次语言组成,分别为: (1) C。区块(blocks) 、语句(statements) 、预处理器(preprocessor) 、

necrazy的专栏 911

《effective c++》读书笔记【一】

最近决心重新打好编程基础,看effectvie c++以弥补大学三年对基础知识的不重视,希望在边看的

Frank_hxc的专栏 648

Effective Modern C++ 读书笔记(一) 类型推导

Deducing Types 模板类型推导 template<typename T> void f(ParamType param); 编译期间,编译器使用expr进行两个类型推导,一个是针对T,另外一个是针对ParamType的。两个类型通常不同。 因为ParamType通常包括对const和reference的修饰 如: template<typename T> void f(const T& param); 模板类型T的推导不仅仅取决于实参,也取决于ParamTyp

小凯的博客 400
上一篇: Sublime Text 2+ Markdown
下一篇: Python 快速入门
张哲BJUT
博客等级 码龄15年 151粉丝 111原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值