C++进阶---C++11

Posted 4nc414g0n

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++进阶---C++11相关的知识,希望对你有一定的参考价值。

C++11

1)初始化

①初始化

struct Point

	int _x;
	int _y;
	Point(int x, int y)
		:_x(x)
		, _y(y)
	
;
class Date

public:
	Date(int year, int month, int day)
		:_year(year)
		, _month(month)
		, _day(day)
	
		cout << "Date(int year, int month, int day)" << endl;
	
private:
	int _year;
	int _month;
	int _day;
;

可以这样初始化:

//int a[] =  1, 2, 3, 4 ;
int a[]  1, 2, 3, 4 ;
//Point p =  1, 2 ;
Point p 1, 2 ;

int* p1 = new int(0);
int* p2 = new int[5]1,2,3,4,5;
Point* p3 = new Point[3]1, 1,  2, 2 ,  3, 3 ;
//需要有初始化列表初始化,底层未封装这种初始化
Date d1(2022, 3, 13);
Date d2 =  2022, 3, 15 ;
Date d3 2022, 3, 15 ;
Date2022,3,15;

int i = 1;
int j =  2 ;
int k 3 ;

C++11里面扩展了初始化使用,基本都可以使用它来初始化,但是建议还是按旧的用法来使用,一般new[]建议使用它来初始化


②std::initializer_list

initializer list用来接收,同时支持迭代器
例如:

auto il =  10, 20, 30 ;
initializer_list<int> il= 10, 20, 30 //支持迭代器:
std::initializer_list<int>::iterator it;  // same as: const int* it
for ( it=il.begin(); it!=il.end(); ++it) 
	cout<< *it <<endl;


以vector为例:
vector的constructor函数

vector (initializer_list<value_type> il,
      const allocator_type& alloc = allocator_type());

vector中要实现新的成员函数vector(initializer_list l)

//C++11实现的initializer_list
typedef T* iterator;
vector(initializer_list<T> l)

	_start = new T[l.size()];
	_finish = _start + l.size();
	_endofstorage = _start + l.size();

	iterator vit = _start;
	typename initializer_list<T>::iterator lit = l.begin();
	while (lit != l.end())
	
		*vit++ = *lit++;
	


2)声明

①auto

auto最初是在C语言中的关键字,用于定义一个自动类型,在栈上,不用自动销毁,现已废弃
在C++中auto为自动推导类型
auto最常用在省略迭代器类型,比如:

initializer_list<T> l;
auto lit = l.begin();

②decltype

关键字decltype将变量的类型声明为表达式指定的类型
比如:

const int x = 1;
double y = 2.2;
decltype(x * y) ret; // ret的类型是double
decltype(&x) p;// p类型是int*

decltype的一些使用使用场景

template<class T1, class T2>
void F(T1 t1, T2 t2)

	decltype(t1 * t2) ret;
	cout << typeid(ret).name() << endl;

③nullptr

在传统C中 ‘NULL’ 是 头文件 stddef.h 中的一个宏,可能被定义为字面常量0,或者被定义为无类型指针(void*)的常量C++98也用的NULL

#ifndef NULL
#ifdef __cplusplus
#define NULL 0
#else
#define NULL ((void *)0)
#endif
#endif

所以我们在遇到这样的代码:

void f(int)

	cout<<"f(int)"<<endl;

void f(int*)

	cout<<"f(int*)"<<endl;

int main()

	f(NULL);
	f((int*)NULL);
	return 0;

第一次打印的是f(int)与我们想打印空指针相悖只有第二次强制类型转换才可以达到预期效果
所以在C++中引入了专门用来表示空指针的nullptr


注意

  1. 在使用nullptr表示指针空值时,不需要包含头文件,因为nullptr是C++11作为新关键字引入的
  2. 在C++11中,sizeof(nullptr) 与 sizeof((void*)0)所占的字节数相同
  3. 为了提高代码的健壮性,在后续表示指针空值时建议最好使用nullptr

3)范围for

底层其实就是迭代器,参考:C++初阶—string类的模拟实现的iterator迭代器 部分

4)智能指针(MARK一下)

5)STL变化

  1. array<int> a1;int a2[10];底层一样,除了实现了迭代器,同时array加了越界assert强制检查,而对于数组,编译器是抽查
  2. forward_list无实际的用处,仅仅比list少用了一个指针,且只支持push_front、pop_front
  3. unordered_map/unordered_set,map和set的hash封装,较多数据时效率更高
  4. 插入函数的右值引用版本(见下)

6)右值引用、移动语义

复习左值引用:C++初阶—C++基础入门概览引用部分
左值/左值引用:

  1. 左值是一个表示数据的表达式(如变量名或解引用的指针),我们可以获取它的地址+可以对它赋值,左值可以出现赋值符号的左边,右值不能出现在赋值符号左边。定义时const修饰符后的左值,不能给他赋值,但是可以取它的地址
  2. 左值引用就是给左值的引用,给左值取别名

无论左值引用还是右值引用,都是给对象取别名
右值/右值引用:

  1. 右值也是一个表示数据的表达式,如:字面常量、表达式返回值,传值返回函数的返回值(这个不能是左值引用返回)等等,右值可以出现在赋值符号的右边,但是不能出现出现在赋值符号的左边,右值不能取地址
  2. 右值引用就是对右值的引用,给右值取别名

例如:

double x=1.1,y=1.2;//x,y是左值
//以下都是右值
12;
x+y;
min(x,y);
//以下是右值引用
int&& a=10double&& b=x+y;
double&& c=min(x,y);

注意:

  1. 赋值运算符的左操作数必须为左值
  2. 右值是不能取地址的,但是给右值取别名后,会导致右值被存储到特定位置(这个别名就变成左值了),且可以取到该位置的地址
  3. 加了const 的右值引用不可被修改(同左值)

左值右值比较:

  1. 左值引用只能引用左值,不能引用右值,但是const左值引用既可引用左值,也可引用右值
  2. 右值引用只能右值,不能引用左值,但是右值引用可以move以后的左值,比如下面的代码:
int a=2;
int&& s=2;
//下面的语句会报错: message : 无法将左值绑定到右值引用
int&& s1=a;
int&& s2=s;
//使用move()将a转换为右值
int&& s3=std::move(a);

右值的应用场景:(以以前我们模拟实现的string为例)
对于只有左值引用形参的函数时,f(1)和f(a)均会匹配void f(const int& a),而当有右值引用形参的函数时f(1)会优先匹配void f(int&& a)

void f(const int& a)

	cout << "void f(const int& a)" << endl;


void f(int&& a)

	cout << "void f(int&& a)" << endl;

int a = 10;
f(1);
f(a);


移动构造

// 移动构造
string(string&& s)
	:_str(nullptr)
	, _size(0)
	, _capacity(0)

	cout << "string(string&& s) -- 移动拷贝" << endl;
	//this->swap(s);
	swap(s);


注意:出了作用域,如果返回对象不在了,不能使用引用返回(左值引用和右值引用都不可以)

以上是关于C++进阶---C++11的主要内容,如果未能解决你的问题,请参考以下文章

我的C/C++语言学习进阶之旅收集关于MODERN C++ 11/14/17/20/23 的一些资料

C++11 字符数组初始化和字符串字面量

托管 C++ 中的逐字字面量? (就像 C# 的 @"blah")

c++ 内存管理 —— delete释放内存的时效性

C++进阶第二十五篇——C++11(列表初始化+变量类型推导+右值引用和移动语义+新的类功能+可变模板参数)

C++进阶第二十五篇——C++11(列表初始化+变量类型推导+右值引用和移动语义+新的类功能+可变模板参数)