笔记③:牛客校招冲刺集训营---C++工程师(5.9 C++新特性)

本文详细介绍了C++11及后续版本中的新特性,重点讲解了智能指针(auto_ptr、unique_ptr、shared_ptr、weak_ptr)及其解决的内存管理问题,移动语义的概念与move()函数的应用,以及Lambda表达式的使用,旨在帮助读者深入理解C++的新功能并提升编程效率。
摘要由CSDN通过智能技术生成

0625

第5章 高频考点与真题精讲

5.1 指针 & 5.2 函数

5.3 面向对象(和5.4、5.5共三次直播课)

5.3.1 - 5.3.11

笔记①:牛客校招冲刺集训营—C++工程师

5.3.12-38

5.6 内存管理①(结合计算机操作系统笔记)

5.7 内存管理②(结合计算机操作系统笔记)

5.7 名称空间、模板

5.8 STL(标准模板库)

笔记②:牛客校招冲刺集训营—C++工程师

5.9 C++新特性

视频课5.9的全部加上视频课5.10的前01:14:39都是关于C++新特性的。

5.9.1 新类型、路径表示

C++ 11 新增了类型 long longunsigned long long,以支持 64 位(或更宽)的整型
新增了类型 char16_tchar32_t,以支持 16 位和 32 位的字符表示;
还新增了”原始“字符串。

表示路径的时候,因为一般的路径都是用反斜杠隔开的,或者包含一些其他类型的符号(问号、逗号等),而路径是使用双引号括起来的,所以就涉及到转义字符的情况,三种方法:

  1. 在每个反斜杠前再加个反斜杠;
  2. R"( 路径 )"把路径括起来;
  3. R"+*( 路径 )+*"把路径括起来。
cout << "C:\\Program Files (x86)\\Application Verifier" << endl;
cout << R"(C:\Program Files (x86)\Application Verifier)" << endl;
cout << R"+*(C:\Program Files (x86)"\Application Verifier)+*" << endl;

5.9.2 统一的初始化(初始化列表)

C++ 11 扩大了用大括号括起的列表(初始化列表)的适用范围,使其可用于所有内置类型用户定义的类型(即类对象)。使用初始化列表时,可添加等号(=),也可不添加

int x = {
   5};
double y {
   2.75};
short quar[5] {
   1, 2, 3, 4, 5};
int * ar = new int [4] {
   2, 3, 4, 5};
class Stump {
   
private:
int roots;
double weight;
public:
Stump(int r, double w) : roots(r), weight(w) {
   }
};
Stump s1(3, 15.6);
Stump s2{
   5, 43.4};
Stump s3 = {
   4, 32.1};

5.9.3 声明

1.关键字auto

auto:自动类型推断(转换)。

	vector<int> v = {
   1, 2, 3, 4, 5};
	//for(vector<int>::iterator it = v.begin(); it != v.end(); ++it){
   
	for(auto it = v.begin(); it != v.end(); ++it){
   
		cout << *it << ", ";
	}
	cout << endl;
2.关键字decltype(declare type)☆☆

先看个例子:

	int a; float b;
	//float c = a * b;
	decltype(a * b) c = a * b;//假如不知道c的类型,可用decltype推导出来
	
	double x;
	int n;
	decltype(x * n) q;//double类型
	decltype(&x) pd;//double*类型

template<typename T, typename U>
void ef(T t, U u) {
   
	decltype(T * U) tu;//
}

decltype变量的类型声明为表达式指定的类型。一般用在模板中。

(以下内容来自C++ Primer Plus(嵌入式公开课)—第8章 函数探幽中的8.5.6 模板函数的发展—关键字decltype
假如有以下模板:

template <class T1, class T2>
void ft(T1 x, T2 y){
   
	...
	?type? xpy = x + y;
	...
}

考虑xpy是什么类型?
可能是T1、T2或者其他类型。
当T1是double型,T2是int型,x+y是double型,xpy是T1类型;
当T1是short型,T2是int型,x+y是int型,xpy是T2类型;
当T1时short型,T2是char型,x+y的结果自动整型提升,xpy是int型。

C++新增的关键字decltype提供了解决方案:

template <class T1, class T2>
void ft(T1 x, T2 y){
   
	...
	decltype(x + y) xpy = x + y;
	...
}

当使用关键字decltype时,为确定类型,编译器必须遍历一个核对表。假如有如下声明:

decltype(expression) var;
decltype(x) y; // 让y的类型与x相同,x是一个表达式

则核对表的简化版如下:
1.如果expression是一个没有用括号括起的标识符,则var的类型与该标识符的类型相同,包括const等限定符:

double x = 5.5;
double y = 7.9;
double& rx = x;
const double* pd;
decltype(x) w;		//w和x的类型相同,double
decltype(rx) u = y; //u和rx的类型相同,double&
decltype(pd) v;		//v和pd的类型相同,const double*

2.如果expression是一个函数调用,则var的类型与函数的返回类型相同:

long indeed(int);
decltype(indeed(3)) m;//m和indeed()函数的返回值类型相同,即long

3.如果expression是一个用括号括起来的标识符,则var为指向其类型的引用
(注意:这里的expression必须是一个左值;如果是个右值,var的类型就是这个右值的类型,而不是它的引用)

expression是左值:
double xx = 4.4;
decltype ((xx)) r2 = xx;//r2是指向括号里的xx的引用,即double&
decltype (xx) w = xx;//w和xx的类型相同,即double

expression是右值:(常量、表达式)
decltype (10) r22;//int
decltype ((10)) r22;//int不是int&,因为10是右值
decltype (xx + 3) ww;//double
decltype ((xx + 3)) ww;//double,不是double&,因为xx + 3是右值

补充:左值&右值
左值:可修改的值,例如普通变量,int m, n;
非左值:不可修改的值,例如常量(10)和表达式(m+3);

4.如果前面的条件都不满足,则var的类型与expression的类型相同:

int j = 3;
int& k = j;
int& n = j;
decltype(j + 6) i1;//i1是int
decltype(100L) i2; //i2是long
decltype(k + n) i3;//i3是int
decltype((k + n)) i4;//i4是int,不是int&,因为k+n是右值

请注意,虽然k和n都是引用,但表达式k + n不是引用,它是两个int的和,是个右值,所以i3int类型;
由于k + n是右值,所以给它加个括号之后,i4的类型跟这个右值的类型相同,而不是它的引用。

3.返回类型后置

C++11 新增了一种函数声明语法:
在函数名和参数列表后面(而不是前面)指定返回类型:

double f1(double, int);
auto f2(double, int) -> double;
// -> double 称为后置返回类型,auto是一个占位符,表示后置返回类型提供的类型

注意:这里的auto是一个占位符,它并不能推导出返回值的类型,因为在写返回值的时候还没有使用过形参,根本无法推导出返回值的类型。

有一个相关的问题是 decltype 本身无法解决的:

template<typename T1, typename T2>
??? gt(T1 x, T2 y) {
   
	...
	return x + y;
}

用decltype来解决:decltype 在参数声明后面,因此x和y位于作用域内,可以使用

template<typename T1, typename T2)
auto eff(T1 x, T2 y) -> decltype(x*y){
   
// decltype 在参数声明后面,因此x和y位于作用域内,可以使用
	...
	return x * y;
}
4.模板别名(using 别名 = )

(这个用的很少,了解下)
对于冗长或复杂的标识符,如果能够创建其别名将很方便。之前,C++ 提供了 typedef:

typedef std::vector<std::string>::iterator itType;

C++ 11 提供了另一种创建别名的语法:

using itType = std::vector<std::string>::iterator;

差别在于,这种方式也可以用于模板部分具体化,但 typedef 不能:

template<typename T>
using arr12 = std::array<T,12>;

上述语句具体化模板array<T,int>,对于下述声明:

std::array<double,12> a1;
std::array<std::string,12> a2

可将它们替换为如下声明:

arr12<double> a1;
arr12<std::string> a2;
5.关键字nullptr

以前是NULL,C++11中变成了nullptr。

5.9.4 智能指针☆☆☆☆☆

视频课中从50:20开始,到01:49:49结束)

第一次涉及到智能指针是在笔记②:牛客校招冲刺集训营—C++工程师中的☆☆☆指针运算符重载(* 和 ->)(写个智能指针类),写了个智能指针类,类中重载解引用*箭头->运算符,并且在析构函数中将new的空间释放掉,就可以避免因为忘记手动delete而带来的内存泄漏问题,所以叫智能指针。

为什么要引入智能指针?

如果在程序中使用 new 从堆(自由存储区)分配内存,等到不再需要时,应使用 delete 将其释放。C++ 引入了智能指针 auto_ptr(C++98), 以帮助自动完成这个过程。智能指针是行为类似于指针的类对象
在使用时(尤其是使用STL),需要更精致的机制,C++ 11 摒弃了 auto_ptr,并新增了三种智能指针:unique_ptrshared_ptrweak_ptr。(严格意义上来说前两种是智能指针,第三种是为了解决第二种智能指针出现的循环引用的问题)

void remodel(std::string & str) {
   
	std::string * ps = new std::string(str);
	// ...
	str = *ps;
	return;
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值