C++新特性——郭炜

统一的初始化方法

变量后面直接跟花括号{}
int arr[3]{1, 2, 3};
vector<int> iv{1, 2, 3};
map<int, string> mp{{1, "a"}, {2, "b"}};
string str{"Hello World"};
int * p = new int[20]{1,2,3};//这种方法推荐使用!
struct A { 
	int i,j; 
	A(int m,int n):i(m),j(n) { } 
}; 
A func(int m,int n ) { return {m,n}; }//这里能知道返回了一个A对象
int main() { A * pa = new A {3,7}; }

成员变量默认初始值

class B {
public:
	int m = 1234;//如果在生成对象时不赋值,默认就是这个值
	int n;
};

auto关键字

用于定义变量,编译起可以自动判断变量的类型
前提是必须赋初值

定义变量不再用类型关键字

auto i = 100; // i 是 int
auto p = new A(); // p 是 A *
auto k = 34343LL; // k 是 long long
//下面这个方法很实用!
map<string,int,greater<string> > mp;
for( auto i = mp.begin(); i != mp.end(); ++i)//自动确定i的类型
	cout << i->first << "," << i->second ;
//i的类型是: map<string,int,greater<string> >::iterator

返回类型的扩充

class A { };
A operator + ( int n,const A & a){ 
	return a; 
}
template <class T1, class T2>
auto add(T1 x, T2 y) -> decltype(x + y) {
	return x+y; //因为有重载,所以这里的返回值可能不是T1或T2,所以用auto更好
}
auto d = add(100,1.5); // d是double d=101.5
auto k = add(100,A()); // d是A类型

decltype 关键字

求表达式的类型
int i;
double t;
struct A { double x; };
const A* a = new A();
decltype(a) x1; // x1 is A *
decltype(i) x2; // x2 is int 
decltype(a->x) x3; // x3 is double
decltype((a->x)) x4 = t; // x4 is double& //加一个()变成了引用,这里是一个奇怪的地方!	

智能指针shared_ptr——托管!

这是一个类模板
通过shared_ptr的构造函数,可以让shared_ptr对象托管一个new运算符返回的指针
shared_ptr<T> ptr(new T)————T *p;
此后ptr就可以像 T* 类型的指针变量一样来使用,即 *ptr 就是用new动态分配的那个对象,而且不必操心释放内存的事
多个shared_ptr对象可以同时托管一个指针,系统会维护一个托管计数。当无shared_ptr托管该指针时,delete该指针。
shared_ptr对象不能托管指向动态分配的数组的指针,否则程序运行会出错

这段代码还不是很懂

struct A { 
	int n;
	A(int v = 0):n(v){ } 
	~A() { cout << n << " destructor" << endl; }
};
int main()
{
	shared_ptr<A> sp1(new A(2)); //sp1托管A(2) 
	shared_ptr<A> sp2(sp1); //sp2也托管 A(2) 
	shared_ptr<A> sp3;//谁也没有托管
	A * p = sp1.get(); //p 指向 A(2)——get()函数返回一个指针!
	sp3 = sp1; //sp3也托管 A(2) 
	sp1.reset(); //sp1放弃托管 A(2)
	if( !sp1 )//判断是否有托管的对象
		cout << "4)sp1 is null" << endl; //这里会输出
	A * q = new A(3);
	sp1.reset(q); // sp1托管q
	shared_ptr<A> sp4(sp1); //sp4托管A(3) 
	shared_ptr<A> sp5;
	//sp5.reset(q);这样会出错
	sp1.reset(); //sp1放弃托管 A(3)
	cout << "before end main" <<endl;
	sp4.reset(); //sp1放弃托管 A(3)
	cout << "end main" << endl;
	return 0; //程序结束,会delete 掉A(2)
}

其他的注意点:对同一指针的托管不会增加该指针的托管计数!

struct A{
	~A() { cout << "~A" << endl; }
};
int main()
{
	A * p = new A();
	shared_ptr<A> ptr(p);
	shared_ptr<A> ptr2;
	ptr2.reset(p); //并不增加 ptr中对p的托管计数
	cout << "end" << endl;
	return 0;
}

空指针nullptr

与NULL类似但略有区别
int main() {
	int* p1 = NULL;
	int* p2 = nullptr; 
	shared_ptr<double> p3 = nullptr;
	if(p1 == p2)
	cout << "equal 1" <<endl;
	if( p3 == nullptr)
	cout << "equal 2" <<endl;
	if( p3 == p2) ; // error 
	if( p3 == NULL)
	cout << "equal 4" <<endl;
	//可以进行类型转换
	bool b = nullptr; // b = false
	int i = nullptr; //error,nullptr不能自动转换成整型
	return 0;
}

基于范围的for循环——类似JAVA

struct A { int n; A(int i):n(i) { } };
int main() {
	int ary[] = {1,2,3,4,5};
	for(int & e: ary) 
	e*= 10;
	for(int e : ary)
	cout << e << ",";
	cout << endl;
	vector<A> st(ary,ary+5);
	for( auto & it: st) 
	it.n *= 10;
	for( A it: st) 
	cout << it.n << ",";
	return 0;
}

右值引用和move语义

右值:不能取地址的表达式,例如临时变量
左值:能取地址的表达式
左值引用:A & r = a 前面学的引用都是左值引用
右值引用:A && r = A();
目的是提高程序运行的效率,减少需要进行深拷贝的对象进行深拷贝的次数。

例子:

class String
{
	public:
	char * str;
	String():str(new char[1]) { str[0] = 0;}//无参构造函数
	String(const char * s) {//有参构造函数
		str = new char[strlen(s)+1];
		strcpy(str,s);
	}
	String(const String & s) {//复制构造函数
		cout << "copy constructor called" << endl;
		str = new char[strlen(s.str)+1];
		strcpy(str,s.str);
	}
	String & operator=(const String & s) {//运算符重载——深拷贝
		cout << "copy operator= called" << endl;
		if( str != s.str) {
			delete [] str;
			str = new char[strlen(s.str)+1];
			strcpy(str,s.str);
		}
		return * this;
	}
	// move constructor——移动构造函数
	String(String && s):str(s.str) {//不再进行深拷贝了——传进来的s可以任意改变都无所谓,因为右值引用很可能是一个临时对象
		cout << "move constructor called"<<endl;
		s.str = new char[1];
		s.str[0] = 0;
	}
	// move assigment
	String & operator = (String &&s) {//这里也不再进行深拷贝了
		cout << "move operator= called"<<endl;
		if (str!= s.str) {
			delete [] str;
			str = s.str;
			s.str = new char[1];
			s.str[0] = 0;
		}
		return *this;
	}
	~String() { delete [] str; }
};
template <class T>//这里的T当做String处理了
void MoveSwap(T& a, T& b) {//move的作用是将左值变成右值
	T tmp(move(a)); // std::move(a)为右值,这里会调用move constructor
	a = move(b); // move(b)为右值,因此这里会调用move assigment
	b = move(tmp); // move(tmp)为右值,因此这里会调用move assigment
}
int main()
{
	//String & r = String("this"); // 左值引用引用右值出错!
	String s;
	s = String("ok"); // String("ok")是右值——临时对象
	cout << "******" << endl;
	String && r = String("this");//把右值给右值引用
	cout << r.str << endl;
	String s1 = "hello",s2 = "world";
	MoveSwap(s1,s2);
	cout << s2.str << endl;
	return 0;
}
输出:
move operator= called
******
this
move constructor called
move operator= called
move operator= called
hello

无序容器(哈希表)

和map一样,查找速度更快!
哈希表插入和查询的时间复杂度几乎是常数
int main()
{
	unordered_map<string,int> turingWinner; //图灵奖获奖名单
	turingWinner.insert(make_pair("Dijkstra",1972));
	turingWinner.insert(make_pair("Scott",1976));
	turingWinner.insert(make_pair("Wilkes",1967));
	turingWinner.insert(make_pair("Hamming",1968));
	turingWinner["Ritchie"] = 1983;
	string name;
	cin >> name; //输入姓名
	auto p = turingWinner.find(name);//很简单的写法哦!这是一个迭代器
	//据姓名查获奖时间
	if( p != turingWinner.end())
	cout << p->second;
	else
	cout << "Not Found" << endl;
	return 0;
}

正则表达式

字符串的一种表达模式——常用于匹配
	regex reg("b.?p.*k");
	.表示任意一个字符
	?表示 . 代表的字符出现01*表示 . 代表的字符出现0或无限次
	
	cout << regex_match("bopggk",reg) <<endl;//输出 1, 表示匹配成功
	cout << regex_match("boopgggk",reg) <<endl;//输出 0, 匹配失败
	cout << regex_match("b pk",reg) <<endl; //输出 1, 表示匹配成功
	regex reg2("\\d{3}([a-zA-Z]+).(\\d{2}|N/A)\\s\\1"); 
	\\d表示这个位置是一个0-9的数字
	{3}表示前面这个数字出现3()代表一个整体
	[a-zA-Z]代表出现有字母构成的一个字符串
	+ 表示前面的内容出现若干次
	(\\d{2}|N/A)表示内容为\\d{2}或者是N/A
	\\s 空格
	\\1 第一个部分 即([a-zA-Z]+)
	
	string correct="123Hello N/A Hello";
	string incorrect="123Hello 12 hello"; 
	cout << regex_match(correct,reg2) <<endl; //输出 1,匹配成功
	cout << regex_match(incorrect,reg2) << endl; //输出 0, 失败

Lambda表达式

形式:
[ 外部变量访问方式说明符 ](参数表) ->返回值类型{
语句组
}

[] 不使用任何外部变量
[=] 以传值的形式使用所有外部变量——这个时候不允许修改这个值!
[&] 以引用形式使用所有外部变量
[x, &y] x 以传值形式使用,y 以引用形式使用
[=,&x,&y] x,y 以引用形式使用,其余变量以传值形式使用
[&,x,y] x,y 以传值的形式使用,其余变量以引用形式使用
“->返回值类型”也可以没有, 没有则编译器自动判断返回值类型。

例子:

int main() 
{
	int x = 100,y=200,z=300;
	cout << [](double a,double b){return a+b;}(1.2,2.5)//后面这个是用的时候传入的参数
	<< endl;
	auto ff = [=,&y,&z](int n) { 
	cout <<x << endl; 
	y++; z++; 
	return n*n; 
	};
	cout << ff(15) << endl;
	cout << y << "," << z << endl;
}
int a[4] = { 4,2,11,33};
sort(a,a+4,[ ](int x,int y)->bool {return x%10 < y%10; });
for_each(a,a+4,[ ](int x) {cout << x << " " ;} ) ;
int main()
{
	vector<int> a { 1,2,3,4};
	int total = 0;
	for_each(a.begin(),a.end(),[&](int & x) {total += x; x*=2;});
	cout << total << endl; //输出 10
	for_each(a.begin(),a.end(),[ ](int x) { cout << x << " ";});
	return 0;
}
实现递归求斐波那契数列第n项:
//这里的function<int(int)>不能用auto代替,因为返回的类型是不确定的!
function<int(int)> fib = [&fib](int n){return n<=2 ? 1 : fib(n-1)+fib(n-2);};
cout << fib(5) << endl; //输出5
function<int(int)> 表示返回值为 int, 有一个int参数的函数
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值