簡體   English   中英

線程中的C ++方法。 傳遞之間的區別:對象,對象的地址,對象的std :: ref

[英]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!

雖然如果我只是簡單地將&conanstd::ref(conan)作為thread t(...)的第二個參數傳遞(而不是傳遞conan ),則輸出僅為:

Conan is attacking for 5!

我有4個疑問:

  1. 為什么我有該對象的2個副本而不是1個?

    我期望通過將對象的實例傳遞給線程的構造函數,該對象將在線程自己的堆棧中被復制一次 ,然后在該副本上調用attack()方法。

  2. 線程的構造函數可以接受對象,地址或std::ref的確切原因是什么? 是否使用此版本的構造函數(我承認我不太了解)

    template< class Function, class... Args > explicit thread( Function&& f, Args&&... args );

    在所有三種情況下?

  3. 如果排除第一種情況(由於效率低下),在&conanstd::ref(conan)之間應該使用什么?

  4. 這是否與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上調用指向成員函數的指針。

如果排除第一種情況(由於效率低下),在&conanstd::ref(conan)之間應該使用什么?

這主要是基於意見的。 盡管第一個版本的編寫時間較短,但它們實際上都在做相同的事情。

這是否與std::bind所需的語法有關?

的種類。 std::bindoperator()也使用std::invoke因此它們具有非常通用的接口。


所有這些都說明您可以使用lambda來給自己一個通用的界面。

thread t(&Warrior::attack, conan, 5);

可以改寫成

thread t([&](){ return conan.attack(5); });

而且,您可以將此表單用於幾乎所有您要調用的其他函數。 我發現看到lambda時更容易解析。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM