关键字和新语法
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;
}