const
const 修饰类成员函数,其目的是防止成员函数修改被调用对象的值,如果我们不想修改一个调用对象的值,所有的成员函数都应当声明为 const 成员函数。
const修饰的类成员函数只能调用const修饰的成员函数。
加const修饰的函数和不加const修饰的函数是两个不同的函数,不可做为“重载”
注意:const 关键字不能与 static 关键字同时使用,因为 static 关键字修饰静态成员函数,静态成员函数不含有 this 指针,即不能实例化,const 成员函数必须具体到某一实例。
noexcept
该关键字告诉编译器,函数中不会发生异常,这有利于编译器对程序做更多的优化。
如果在运行时,noexecpt函数向外抛出了异常(如果函数内部捕捉了异常并完成处理,这种情况不算抛出异常),程序会直接终止,调用std::terminate()函数,该函数内部会调用std::abort()终止程序。
C++的异常处理
C++中的异常处理是在运行时而不是编译时检测的。为了实现运行时检测,编译器创建额外的代码,然而这会妨碍程序优化。
在实践中,一般两种异常抛出方式是常用的:
一个操作或者函数可能会抛出一个异常;
一个操作或者函数不可能抛出任何异常。
override:
修饰虚函数强制重写,被override修饰的虚函数不重写会报编译错误------------恢复内容开始------------
noexcept
该关键字告诉编译器,函数中不会发生异常,这有利于编译器对程序做更多的优化。
如果在运行时,noexecpt函数向外抛出了异常(如果函数内部捕捉了异常并完成处理,这种情况不算抛出异常),程序会直接终止,调用std::terminate()函数,该函数内部会调用std::abort()终止程序。
C++的异常处理
C++中的异常处理是在运行时而不是编译时检测的。为了实现运行时检测,编译器创建额外的代码,然而这会妨碍程序优化。
在实践中,一般两种异常抛出方式是常用的:
一个操作或者函数可能会抛出一个异常;
一个操作或者函数不可能抛出任何异常。
override:
修饰虚函数强制重写,被override修饰的虚函数不重写会报编译错误
move
C++的传参背景:
C++传值默认是copy
临时变量在C++11里被定义为rvalue, 右值, 因为没有对应的变量名存他们(同时有对应变量名的被称为lvalue, 左值)
move的语意:参考链接
(1)成员变量内部的指针指向"temporary str1"所在的内存
(2)临时变量内部的指针指向成员变量以前所指向的内存
(3)最后临时变量指向的那块内存再被回收
上面这个操作避免了一次copy的发生, 其实它就是所谓的move语义.
传临时变量的时候, 可以传T &&, 叫rvalue reference(右值引用), 它能接收rvalue(临时变量), 之后再调用std::move就避免copy了.
std::move()方法来将左值转换为右值
移动语义对swap()函数的影响也很大,之前实现swap可能需要三次内存拷贝,而有了移动语义后,就可以实现高性能的交换函数了。
template <typename T>
void swap(T& a, T& b)
{
T tmp(std::move(a));
a = std::move(b);
b = std::move(tmp);
}
如果T是可移动的,那么整个操作会很高效,如果不可移动,那么就和普通的交换函数是一样的,不会发生什么错误,很安全。
移动构造和拷贝构造: 参考链接
移动构造:不重新分配一块新的空间将要拷贝的对象复制过来,而是“偷”过来麻将自己的指针指向别人的资源,然后将别人的指针修改为nullptr。如果不将别人的指针修改为空,那么临时对象析构的时候就会释放掉这个资源,偷也白偷了
forward完美转发
所谓转发,就是通过一个函数将参数继续转交给另一个函数进行处理,原参数可能是右值,可能是左值,如果还能继续保持参数的原有特征,那么它就是完美的。
emplace_back
emplace_back()可以直接通过构造函数的参数构造对象,但前提是要有对应的构造函数。可以减少拷贝