在以下代碼中:
#include <iostream>
#include <thread>
using namespace std;
class tester {
public:
tester() {
cout << "constructor" << this << "
"。
}
tester(const tester& other) {
cout << "copy cons. "/span> << this << "
"。
}
~tester() {
cout << "destructor" << this << "
"。
}
void print() const{
cout << "print" << this << "
"。
}
};
int main() {
tester t;
cout << " before lambda
"。
thread t2( [=] {
cout << " thread start
"。
t.print()。
cout << " thread end
"。
})。
t2.join()。
cout << " after join" << endl;
return 0;
}
當用cl.exe編譯時(在Windows上),我得到如下結果:
constructor 012FFA93
在lambda之前
復制弊端。 012FFA92
抄襲弊端。 014F6318
解構器 012FFA92
執行緒開始
列印 014F6318
執行緒結束
解構器 014F6318
連接后
解構器012FFA93
而用g (在WSL上)我得到:
constructor 0x7ffff5b2155e
在lambda之前
拷貝弊端。 0x7ffff5b2155f
抄襲弊端。 0x7ffff5b21517復制cons。
復制弊端。 0x7fffedc630c8 拷貝 cons.
解構器 0x7ffff5b21517
解構器0x7ffff5b2155f。
執行緒開始
列印0x7fffedc630c8
執行緒結束
解構器0x7fffedc630c8
連接后
解構器0x7ffff5b2155e
我希望
[=]捕獲將正好創建tester的1個副本。為什么會有幾個副本被立即銷毀?為什么MSVC和GCC之間會出現分歧?這是未定義的行為還是什么?
uj5u.com熱心網友回復:
標準要求傳遞給std::thread建構式的可呼叫程式是有效的可復制的([thread.thread.constr])
規定。以下都是真的。
is_constructible_v<decay_t<F>, F>/code>- [...]
is_constructible_v<decay_t<F>, F>與is_copy_constructible相同(或者說,它是反過來的)。
這是為了允許實作者自由地傳遞可呼叫程式,直到它到達被呼叫的位置。(事實上,標準本身建議可呼叫程式至少被復制一次。
由于 lambda 被編譯成一個多載了函式呼叫運算子的小類(一個 functor),每次你的 lambda 被復制時,它將創建一個捕獲的 tester 實體的副本。
如果你不希望復制發生,你可以在捕獲串列中取一個對你的實體的參考來代替:
thread t2([&ref = t] {
cout << " thread start
"。
ref.print()。
cout << " 執行緒結束
"。
})。
實時演示
輸出:
constructor 0x7ffdfdf9d1e8
在lambda之前
執行緒開始
print 0x7ffdfdf9d1e8 λ thread start
執行緒結束
連接后
解構器0x7ffdfdf9d1e8
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/321875.html
標籤:
