[英]When does the conversion happen when passing arguments to thread function?
在閱讀一本關於 c++ 多線程編程的書時,我遇到了下面的一個示例。
void f(int i,std::string const& s);
void oops(int some_param)
{
char buffer[1024];
sprintf(buffer, "%i",some_param);
std::thread t(f,3,buffer);
t.detach();
}
在這種情況下,它是指向新線程的局部變量緩沖區的指針,並且很有可能 function oops 將在緩沖區轉換為新線程上的 std::string 之前退出,從而導致到未定義的行為。
我知道它是 char* 類型的參數緩沖區,而不是 std::string 被復制到線程 t 的內部存儲中。 讓我感到困惑的是,即使已經構造了線程 t,也有可能沒有發生從 char* 到 std::string 的轉換。 那么什么時候會發生轉換呢? 是在操作系統計划執行線程之前嗎?
正如您所說,數組參數衰減為char*
,然后為線程復制。 更具體地說,新創建的線程基本上執行以下表達式:
std::invoke(auto(std::forward<F>(f)), auto(std::forward<Args>(args))...)
其中f
和args
是std::thread
構造函數的參數,而auto(/*...*/)
是新的 C++23 語法,它從參數創建參數衰減類型的純右值(並具體化一個臨時的 object 綁定到std::invoke
的參數中的引用時)。
但是,在此評估中,臨時對象auto(/*...*/)
的具體化是在線程構造函數的調用者的上下文中執行的,並且對std::invoke
的調用的開始與std::thread
構造函數。
這意味着auto(/*...*)
衰減參數副本是在線程開始執行之前制作的,但其他一切都是作為新執行線程的一部分發生的。
所以auto(buffer)
將給出一個char*
類型的臨時 object ,它一直存在到線程 function 調用結束(因為臨時對象一直存在到創建它們的完整表達式結束)。 然后std::invoke
並引用這個臨時 object 作為參數。 此調用發生在新創建的執行線程中,並且此處的所有內容都與原始線程中執行的 rest 不同步。
std::invoke
基本上調用復制的f
作為第一個參數並將另一個 arguments 轉發給f
。 現在,由於您的f
期望std::string const&
作為第二個參數,但std::invoke
會將其傳遞一個char*
作為參數,因此將從char*
初始化一個臨時的std::string
,用於引用綁定至。 因此,這種構造發生在std::invoke
調用的上下文中,該調用已經與主線程中指針指向的數組的潛在破壞不同步。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.