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;
}