[英]C++ method in thread. Difference between passing: object, object's address, std::ref of object
我正在嘗試在C ++線程中執行對象的方法。
通過將方法的地址和對象(或對象的地址,或std :: ref(my_obj))傳遞給線程的構造函數,我能夠做到這一點。
我觀察到,如果傳遞對象而不是對象的地址或std :: ref(my_obj),則該對象將被復制兩次 (我在復制構造函數中打印一些信息以查看該信息)。
這是代碼:
class Warrior{
string _name;
public:
// constructor
Warrior(string name): _name(name) {}
// copy constructor (prints every time the object is copied)
Warrior(const Warrior & other): _name("Copied " + other._name){
cout << "Copying warrior: \"" << other._name;
cout << "\" into : \"" << _name << "\"" << endl;
}
void attack(int damage){
cout << _name << " is attacking for " << damage << "!" << endl;
}
};
int main(){
Warrior conan("Conan");
// run conan.attack(5) in a separate thread
thread t(&Warrior::attack, conan, 5);
t.join(); // wait for thread to finish
}
我在這種情況下得到的輸出是
Copying warrior: "Conan" into : "Copied Conan"
Copying warrior: "Copied Conan" into : "Copied Copied Conan"
Copied Copied Conan is attacking for 5!
雖然如果我只是簡單地將&conan
或std::ref(conan)
作為thread t(...)
的第二個參數傳遞(而不是傳遞conan
),則輸出僅為:
Conan is attacking for 5!
我有4個疑問:
為什么我有該對象的2個副本而不是1個?
我期望通過將對象的實例傳遞給線程的構造函數,該對象將在線程自己的堆棧中被復制一次 ,然后在該副本上調用attack()
方法。
線程的構造函數可以接受對象,地址或std::ref
的確切原因是什么? 是否使用此版本的構造函數(我承認我不太了解)
template< class Function, class... Args > explicit thread( Function&& f, Args&&... args );
在所有三種情況下?
如果排除第一種情況(由於效率低下),在&conan
和std::ref(conan)
之間應該使用什么?
這是否與std::bind
所需的語法有關?
為什么我有該對象的2個副本而不是1個?
旋轉線程時,參數將復制到線程對象中。 然后將這些參數復制到創建的實際線程中,因此您有兩個副本。 這就是為什么要傳遞函數通過引用獲取的參數時必須使用std::ref
原因。
線程的構造函數可以接受對象,地址或std :: ref的確切原因是什么? 是否使用此版本的構造函數(我承認我不太了解)
std::thread
基本上通過如下調用來啟動新線程
std::invoke(decay_copy(std::forward<Function>(f)),
decay_copy(std::forward<Args>(args))...);
std::invoke
用於處理所有不同種類的可調用對象,其中之一是當它具有成員函數指針和對象時,並且會適當地調用該函數。 它還了解std::reference_wrapper
並且可以處理在對象的std::reference_wrapper
上調用指向成員函數的指針。
如果排除第一種情況(由於效率低下),在
&conan
和std::ref(conan)
之間應該使用什么?
這主要是基於意見的。 盡管第一個版本的編寫時間較短,但它們實際上都在做相同的事情。
這是否與
std::bind
所需的語法有關?
的種類。 std::bind
的operator()
也使用std::invoke
因此它們具有非常通用的接口。
所有這些都說明您可以使用lambda來給自己一個通用的界面。
thread t(&Warrior::attack, conan, 5);
可以改寫成
thread t([&](){ return conan.attack(5); });
而且,您可以將此表單用於幾乎所有您要調用的其他函數。 我發現看到lambda時更容易解析。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.