C++

cpp primer知识点记录

Posted by BY Yuaika on April 11, 2022

C++ Primer

对C++ Primer的部分内容的记录

0.gcc编译cpp程序的过程

https://www.cnblogs.com/burner/p/gcc-bian-yiccde-si-ge-guo-cheng.html

1.一些关键字

constexpr类型:由编译器来验证变量的值是否为一个常量表达式

类型别名:typedef,using

类型推导:auto,decltype

预处理:#ifdef,#ifndef,#endif,#define

2.命名空间

namespace

C++11引入内敛的命名空间,用途:区分多个不同版本的代码

使用using声明便捷使用命名空间的成员,也可使用别名,注意避免冲突。

3.跳转语句

break语句负责终止离它最近的while,do while,for或switch语句,并从这些语句之后的第一条语句开始继续执行。

continue语句终止最近的循环中的当前迭代并立即开始下一次迭代。

goto语句能无条件跳转到同一函数内的另一条语句,不要使用。

return语句终止当前正在执行的函数并将控制权返回到调用该函数的地方。能为返回类型是非常量引用的函数的结果赋值。

4.异常处理

try throw catch

5.类型处理

static_cast,const_cast,reinterpret_cat,dynamic_cast

static_cast改变底层const之外的属性,const_cast只能改变底层const。

6.调试帮助(6.5.3节,215页)

assert与NDEBUG

7.lambda表达式

基本形式:[capture list] (parameter list) -> return type { function body },其中参数列表与返回类型可以省略。

lambda表达式的捕获方式分为:值捕获,引用捕获与隐式捕获。

例子:
(1) 查找第一个长度大于等于sz的元素
auto wc = find_if(words.begin(), words.end(), [sz](const string &a){return a.size()>=sz;});
(2) 使用for_each函数 
for_each(wc, words.end(), [](const string &a){cout<<a<<" ";});
(3) 捕获this指针
std::sort(v.begin(), v.end(), [this](auto a, auto b){ return this->cmp(a, b);});

lambda表达式的使用场合:只在一两个地方使用的简单操作,需要捕获局部变量的场合。

如果要为函数提供局部变量,需要借助bind函数。

bind函数接受一个可调用对象,生成一个新的可调用对象。

bind的调用形式:auto newCallable = bind(callable, arg_list);

arg_list中的参数可能包括占位符_n,在命名空间std::placeholders中定义。

8.类的设计

8.1.动态内存管理类

new将内存分配与对象构造组合在了一起,delete将对象析构和内存释放组合在了一起。

为将内存分配与对象构造分离,使用标准库allocator类。

一个动态内存管理类(如13.5节,465页)定义三个指针成员指向其元素所使用的内存:

  • elements,指向分配的内存中的首元素
  • first_free,指向最后一个实际元素之后的位置
  • cap,指向分配的内存末尾之后的位置

需要的工具函数:

  • alloc_n_copy会分配内存,拷贝一个给定范围中的元素
  • free会销毁构造的元素并释放内存
  • check_n_alloc会保证至少有容纳一个新元素的空间
  • reallocate在内存用完时会分配新的内存;在重新分配内存的过程中使用移动而不是拷贝元素

8.2.拷贝控制

  • 拷贝构造函数,拷贝赋值运算符,析构函数。
使用default与delete:
struct NoCopy{
	NoCopy() = default;
	NoCopy(const NoCopy &) = delete;
	NoCopy& operator=(const NoCopy &) = delete;
	~NoCopy() = default;
}
  • 注意引用计数与swap函数的设计。

  • 移动构造函数,移动赋值运算符。

使用std::move将左值转化为右值。

在一些情况下对象拷贝后就立即销毁了,这个时候要使用移动操作。

为StrVec类定义移动构造函数,使用noexcept告诉标准库移动构造函数可以安全使用
StrVec::StrVec(StrVec &&s) noexcept
:elements(s.elements), first_free(s.first_free), cap(s.cap)
{
	s.elements=nullptr; s.first_free=nullptr; s.cap=nullptr;
}

8.3

  • 常量对象,以及常量对象的引用或指针都只能调用常量成员函数
重载下标运算符时需要定义两个版本:
std::string& operator[](std::size_t n) { return elements[n]; }
const std::string& operator[](std::size_t n) const { return elements[n]; }
  • 函数调用运算符
struct absInt
{
	int operator() (int val) const {
		return val<0 ? -val : val;
	}
};

int i= -42; absInt absObj;
int abs_i = absObj(i);

编译器会将lambda表达式翻译成一个未命名类的未命名对象。

8.4 OOP

  • 继承,多态,抽象基类
  • 多重继承,虚继承

8.5 模板

  • 可变参数模板
  • 模板特例化

9.其它

  • 使用tuple组合一系列数据
  • 使用bitset处理二进制位
  • 正则表达式regex
  • C++程序不应该使用库函数rand,而应该使用default_random_engine类和恰当的分布类对象
  • 重载new与delete