计算机 / 读书笔记 · 2021年12月22日 0

数据结构与算法分析C++语言描述 Programming: A General Overview

C++ Classes

explicit

对于只有一个参数的构造函数,应该将其声明为explicit,以避免隐式转换带来的难以查找的BUG。

mutable

C++中mutable关键字存在的必要性是什么? – invalid s的回答 – 知乎 https://www.zhihu.com/question/64969053/answer/226142449

声明为mutable的成员变量,可以在const成员函数中被修改。

声明变量时尽量使用花括号初始化

像下面的代码,可能本意是想声明一个变量,但实际上却是声明了一个函数:

IntCell obj4();

而用花括号初始化,则没有歧义:

IntCell obj4{};

使用initializer list初始化vector

vector<int> daysInMonth = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

或者不需要使用等号:

vector<int> daysInMonth{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

C++ Details

动态创建对象

m = new IntCell();
m = new IntCell{}; // C++11
m = new IntCell;

上述3种创建对象的方法都可以用。

左值,右值和引用

左值:标识了一个非临时对象的表达式。

右值:标识了一个临时对象或者不和任何对象关联的表达式。

函数的返回值可能是左值(如*ptrarr[x]cin>>x>>y),也可能是右值。

传递参数

call-by-value

call-by-constant-reference

call-by-lvalue-reference

call-by-rvalue-reference

返回值(Return Passing)

return-by-value

return-by-reference

std::swap与std::move

通过右值引用来实现swap:

void swap(vector<string> &x, vector<string> &y)
{
  vector<string> tmp = static_cast<vector<string>&&>(x);
  x = static_cast<vector<string>&&>(y);
  y = static_cast<vector<string>&&>(tmp);
}

或者使用move函数也是一样的效果:

void swap(vector<string> &x, vector<string> &y)
{
  vector<string> tmp = std::move(x);
  x = std::move(y);
  y = std::move(tmp);
}

The Big Five

C++为每个类提供的5个带有默认实现的函数:destructor,copy constructor,move constructor,copy assignment operator,move assignment operator。

destructor

默认实现对每个类成员调用析构函数。

Copy Constructor and Move Constructor

用于在声明一个对象的时候,将这个对象初始化为另一个对象所处的状态。如果另一个对象是左值,那么调用的是Copy Constructor,如果另一个对象是右值,那么调用的是Move Constructor。

有3种应用场景,

1.声明的时候;

IntCell B = C;
IntCell B{C};

上面两种声明方式等价。

2.作为函数的参数并且使用值传递的时候(不能是通过引用传递参数);

3.作为函数的返回值并且是return by value(不能是返回引用);

copy constructord的默认实现对类成员依次调用各自的copy constructor。

move contructor的默认实现对类成员依次调用copy constructor或者move constructor(如果相应的类成员具有move constructor)。

Copy Assignment and Move Assignment (operator=)

对于lhs=rhs这种表达式,如果rhs是左值,那么就调用copy assignment operator,如果rhs是右值,那么就调用move assignment operator。

copy assignment operator的默认实现对类的每一个成员调用其相应的copy assignment operator。

move assignment operator的默认实现对类成员调用copy assignment operator或者move assignment operator(如果相应的类成员具有move assignment operator)。

对于big five的5个函数,要么就都用默认的,要么就重写其中的某些函数并将其余的标记为default或者delete

copy assignment operator常按照copy and swap idiom实现。

big five5个函数的signature:

destructor

~ class-name ();	
virtual ~ class-name ();	
decl-specifier-seq(optional) ~ class-name () = default;	// since c++11
decl-specifier-seq(optional) ~ class-name () = delete;	// since c++11
attr(optional) decl-specifier-seq(optional) id-expression ( void(optional) ) except(optional) attr(optional) requires-clause(optional);	// since c++20

copy constructor

class-name ( const class-name & );
class-name ( const class-name & ) = default;	// since c++11
class-name ( const class-name & ) = delete;     // since c++11

move constructor

class-name ( class-name && );
class-name ( class-name && ) = default;	
class-name ( class-name && ) = delete;	

copy assignment operator

class-name & class-name :: operator= ( class-name );
class-name & class-name :: operator= ( const class-name & );
class-name & class-name :: operator= ( const class-name & ) = default;	// since c++11
class-name & class-name :: operator= ( const class-name & ) = delete;  // since c++11

move assignment operator

class-name & class-name :: operator= ( class-name && );
class-name & class-name :: operator= ( class-name && ) = default;	
class-name & class-name :: operator= ( class-name && ) = delete;	

实现move assignment operator或者move constructor会导致copy assignment operator和copy constructor的默认实现被删除;

同样实现copy assignment operator和copy constructor也会导致move assignment operator和move constructor的默认实现被删除。