關鍵字和新語法
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;
}