C++:14.C++11 新标准:foreach、右值引用&&、lambda表达式、语言级别的线程与锁

关键字和新语法

1、delete      指定删除类的成员方法        

在类的成员方法后面写  = delete  就将该成员方法删除,用户无法调用。

智能指针unique_ptr就是将对象的拷贝构造和operator=  delete删除了


2、auto        自动的 根据右表达式,自动推倒出左边变量的类型。

auto it = vec.begin()   根据等号右侧的函数推出左侧的类型
相当于 vector<int>::iterator it = vec.begin()

3、nullptr     专门给指针赋空值,不是0,不会像NULL一样,无法区分是整数0还是0地址。  NULL是宏定义的0.

以后写char *p = NULL;
就应该写成 char *p = nullptr;

4、foreach    以简单的方式遍历容器   其底层都转换成了迭代器的遍历方式。

int array[20] = { 12, 4, 5, 67, 8, 90 };

虽然叫foreach但使用方式如下:
for (int val : array)  相当于for(int*p = array; p<array+20; ++p)
{
    cout << val << " ";
}
cout << endl;

5、右值引用 &&

const int &c = 20;  左值引用  不能修改临时量的值

int &&d = 20;         右值引用  可以修改临时量的值

对编译器来讲这俩玩意一样。   

1)右值引用可以直接接受无法取地址的东西。而普通的引用右侧需要有地址。

int &sd = 10; 报错

int &&d = 20;

2)有地址的匹配左值引用,不能匹配右值引用。

      没地址的优先匹配右值引用,没有右值引用,则匹配左值引用。

void func(const int &a)
{
	cout << "func(const int&)" << endl;
}
void func(int &&a)
{
	cout << "func(int&&)" << endl;
}
int main()
{
	int a = 10;
	func(a);      有地址匹配func(const int&)
	func(30);     立即数没有地址优先匹配func(int&&),如果没有该函数则匹配func(const int&)

	return 0;
}

3)可以使用在拷贝构造和赋值函数传参里面使用右值引用(效率高)。

当然原来的不要删,解决浅拷贝问题,要两个同时有,编译器会自己使用效率高的方法。

如果右值是临时对象(也就是马上就要消失的对像)的话,编译器会自动调用使用右值引用的拷贝构造与赋值。

class Test
{
public:
	Test(int data=10) :ptr(new int(data))
	{
		cout << "Test()" << endl;
	}
	~Test()
	{
		delete ptr;
		cout << "~Test()" << endl;
	}
	Test(const Test &src)  左值拷贝构造
	{
		ptr = new int(*src.ptr);  防止浅拷贝的发生,申请与原来一样大的空间。
		cout << "Test(const Test&)" << endl;
	}
	Test(Test &&src)      右值拷贝构造
	{
		ptr = src.ptr;   直接指向
		src.ptr = NULL;  并让原来的指向空,因为能调用右值的肯定是即将要销毁的。
		cout << "Test(Test&&)" << endl;
	}
	Test& operator=(const Test &src)  左值赋值重载
	{
		cout << "operator=(const Test&)" << endl;
		if (this == &src)
                {
			return *this;
                }
		delete ptr;

		ptr = new int(*src.ptr);
		return *this;
	}
	Test& operator=(Test &&src)  右值赋值重载
	{
		cout << "operator=(Test&&)" << endl;

		delete ptr;

		ptr = src.ptr;
		src.ptr = NULL;

		return *this;
	}
private:
	int *ptr;
};

4)右值引用不会默认产生。

临时对象  =》  拷贝构造或者operator=的时候,一律使用右值引用参数的成员方法

5)move

可以将普通对象转换为临时对象,可以引用右值引用的赋值。

再前面智能指针博文讲到unique_ptr,其中体到可以使用move函数来进行权限的转移,就是利用右值引用的内容,进行的转移。


6、智能指针:

auto_ptr    :     直接让最新的auto_ptr唯一持有资源

scoped_ptr  :  把拷贝构造和operator=给private化了

unique_ptr  :   禁止了通作用域对象的拷贝构造和operator=  delete删除了
                       但是提供了右值引用版本的拷贝构造和operator=


7、lambda表达式

以函数的形式存在于表达式中。相当于函数对象。

可以方便的定义和创建匿名函数

[捕获外部变量列表] (形参列表) -> 返回类型 { 函数体 }

bool cmp(int a, int b)
{
    return  a < b;
}

int main()
{
    泛型算法中:
    sort(vec.begin(), vec.end());默认是从小到大排序
    
    其本质就是:
    sort(vec.begin(), vec.end(),less<int>());
    那自己写的函数解释上面的:
    sort(myvec.begin(), myvec.end(), cmp); // 旧式做法

    如果你想从大到小排序:
    sort(vec.begin(), vec.end(),greater<int>());

    如果使用lambda表达式:
    sort(lbvec.begin(), lbvec.end(), [](int a, int b) -> bool { return a < b; });   // Lambda表达式
}

8、语言级别的线程、锁

而在C++中无法使用linux中的线程与锁。而C++11中为我们提供了语言级别的线程与锁。使用方式与linux中一致。

语言级别的线程:
#include <thread>

void threadfun1()
{
	cout << "threadfun1 - 1\r\n" << endl;
	this_thread::sleep_for(chrono::seconds(1));  sleep1秒
	cout << "threadfun1 - 2" << endl;
}


void threadfun2(int iParam, std::string sParam)
{
	cout << "threadfun2 - 1" << endl;
	this_thread::sleep_for(chrono::seconds(5));  sleep5秒
	cout << "threadfun2 - 2" << endl;
}

int main()
{
	thread t1(threadfun1);             创建线程t1,相当于Linux中:pthread_create
	thread t2(threadfun2, 10, "abc");  创建线程t2

	t1.join();                         线程悬挂,相当于Linux中:pthread_join
	cout << "join" << endl;

	t2.detach();                       成线程分离,相当于Linux中:pthread_detach
	cout << "detach" << endl;

	cout << "main thread done!" << endl;
}

头文件:
#include <thread>
#include <mutex>

以一个任务的形式理解:
模拟三个窗口卖票,要求,1.每个窗口都能卖票, 2.票的序号打印应该递减的
每卖完一张票,窗口休息50ms
睡眠的代码:this_thread::sleep_for(std::chrono::seconds(1));

注:通常情况下我们执行代码前先上锁lock(),执行完后再解锁unlock()。

但着也会出现程序异常终止,导致死锁的情况。所以我们使用更为优秀的   lock_guard与unique_lock。

unique_lock 与lock_guard都能实现自动加锁与解锁功能,但是std::unique_lock要比std::lock_guard更灵活,但是更灵活的代价是占用空间相对更大一点且相对更慢一点。

语言级别的锁:

// 定义一个线程共享的互斥锁   lock_guard   unique_lock
mutex thread_mutex;

// 车站窗口卖票
int ticket_count = 10;

// 线程函数
void sell_ticket_window(int no)
{
	while (ticket_count > 0)
	{
		//thread_mutex.lock();一般情况下的加锁
		{ 你会发现这里有个括号不知道是干嘛的。巧妙了,出了这个括号相当于出了作用域,锁自己就释放了
			//lock_guard<mutex> lock(thread_mutex); 可以类比于socped_ptr
			unique_lock<mutex> lock(thread_mutex);  可以类比于unique_ptr
			cout << "窗口" << no << "卖出第" << ticket_count << "张票!" << endl;
			if (ticket_count > 0)
                        {
				ticket_count--;
                        }
			//thread_mutex.unlock();一般情况下的解锁
		}
		this_thread::sleep_for(chrono::milliseconds(50));休息50ms 
	}
}

int main()
{
	thread t1(sell_ticket_window, 1);//创建三个线程,模拟三个窗口
	thread t2(sell_ticket_window, 2);
	thread t3(sell_ticket_window, 3);

	t1.join();
	t2.join();
	t3.join();

	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_41214278/article/details/84502679