引用和指針:
陷進一:不要用引用和指針,因為位址可以被主線程運作完後釋放了。
陷阱二:将對象傳遞給子線程時,可能主線程都運作完了,對象還沒建構。
通過源碼可知,thread類禁用了拷貝構造函數,但支援對象move
帶參架構函數接受的值是右值引用。非帶參和move的線程都是非joinable的。
指針變量如果用detach,很可能主線程結束了,子線程讀取指針變量發生錯誤。
都是右值引用,為什麼int安全,int*類型不安全:
主線程中的i=1和int *p在傳參時應該都是傳的臨時值。
int* && pp=p後,其實最終通路的資料還是i,如果 i 釋放了,那麼p的副本pp也會通路失敗。
int& i;由于子線程不接受左值,主線程會根據左值生成臨時值,然後右值引用=臨時值。
右值引用就是對臨時對象的引用,右值引用在臨時對象釋放後,還是能更改右值引用所引用的值。下面的代碼就是主線程負責申請臨時空間,然後通過右值引用拿來用。
string& pmybuf=string(mybuf):
通過上面分析,首先得到 pmybuf 的副臨時對象,然後把 pmybuf 副本轉換為右值引用。就類似函數參數要求int ,但傳過來的是double。
id是個數字,每個線程實際上都對應着一個數字,而且每個線程對應的數字都不同,也就是說不同的線程id必然是不同的;
線程id可以通過c++标準庫裡的函數來擷取。std::this_thread::get_id().
thread類直接包裝了一個pthread_t,在linux下實際是unsigned long int。
用了一個std::unique_ptr來包裝使用者定義的線程函數:
如果thread()中的參數不是線程函數需要的類對象,
運作結果:
由此可知,類型轉換是在線上程中進行的(之前的分析也推出這個結論),那麼久帶來了一個問題:
主線程已經吧var的臨時對象給子線程了,但是子線程還沒構造a對象(比如時間片還沒輪到子線程),主線程久執行完了,那臨時對象也肯定會銷毀,這種情況就會導緻程式異常。
為什麼不讓子線程生成臨時對象呢:也就是可能子線程的時間片還沒到,沒機會生成臨時對象。(其實是我猜的)
修改代碼:
主線程:
構造函數:将var轉換成a類;拷貝構造:根據a生成a的臨時對象;
子線程:
const a& a=臨時a對象後:const a& 可以接受左值引用也可以接受右值引用
如果參數不用const a&,會調用兩次a的拷貝構造函數,子線程會多調用一次拷貝構造函數。a a=臨時a對象。
上面代碼雖然傳遞的參數是引用,但是當它在子線程中執行時并不會影響主線程的變量。也就是說mybuf仍然是拷貝出來的,不是主線程傳遞對象的引用。
在主線程中又執行了拷貝構造函數
增加std::ref()後
心之所願,永不相忘