2017-04-05 43 views
1

就我所知,調用構造函數/析構函數的唯一區別取決於實例化順序。但是,標準的「普通」用戶類和類之間是否還有其他區別?用戶定義的類和std類有區別嗎?

比方說,我有一個叫做myStackOverflow的類,然後我實例化了這個類的一個對象。我也有一個類型爲std::thread的對象。這些對象的構造函數或析構函數的調用方式有什麼不同嗎?

我問的主要原因是根據C++ standard(第30.3.2.3節)join()不在線程析構函數中調用。你可以閱讀爲什麼here。但在this回答stackoverflow它被提到將std::thread包裝在另一個類中,然後在這個新的包裝類的析構函數中調用join()。我不明白這將如何解決任何問題。析構函數仍然是一個析構函數,在std::thread的析構函數中調用join()的危險仍然存在。

唯一有意義的方法是調用這兩種不同類型的析構函數的方式有所不同。

+3

有沒有區別 – Justin

+6

我覺得你過於簡單化和歪曲。如果你編寫自己的代碼,那麼*你*可以決定在你的情況下加入析構函數是否合適。但是,這並不意味着加入析構函數總是適合每個*情況下的每個用戶。在自動加入是一個問題的情況下,你當然會*不*使用加入包裝。 –

+0

你鏈接的答案實際上並不是說在析構函數中調用'join'。它表示將線程包裝在另一個類中,「這將在銷燬時具有期望的行爲」。如果您希望加入的行爲,並且涉及到的折衷方案可以,您可以這樣做。它不會解決在析構函數中調用'join'的問題,答案並不會聲稱它會。 – user2357112

回答

0

好的@Ali,讓我們簡單介紹一些事情(術語)。

namespace std - 是一個簡單的命名空間,如:

namespace my_namespace { 
    int my_integer; 
}; 

包含噸有用的類的程序員,通過超過於強大的人寫的,而且,你知道它應該是儘可能靈活(後來的「聲明1「),casue不同的人有不同的需求。

當然,它遵守C++標準的一般規則,因爲它的內容也是。


現在讓我們來談談您想要的std::thread

其簡單的類代表a single thread of execution。它可以讓你execue在「外太空」的功能,並與我們的抽象的「外太空」保持聯繫,還處理了一些數據:

  • _id - 線程ID
  • _handle - 祕密變量,它是主要用於與「外太空」
  • ,當然它使一些數據 關於執行的狀態(是否有任何實體現在執行某處 的「外太空」,其中的關鍵使我們)

如果你看起來some references在更多的細節,並牢記我們的「聲明1」,你會發現如下信息:

  • std::thread對象也可以是不代表任何線程狀態」
  • 「沒有兩個std::thread對象可以表示相同的執行線程; std::thread不是CopyConstructible或CopyAssignable,雖然它是MoveConstructible和MoveAssignable。「

現在你應該得出一個結論,即std::thread變量和執行實體是分開的,但試圖刪除附加到一個執行實體std::thread變量拋出異常。

但當實體執行結束,std::thread變量保持活着,並且可以連接到任何其他實體

爲theese需要有以下方法:

join() // waits for a thread to finish its execution 
// if it is attached to something, the code execution will not go futher until our entity finishes its execution. 

detach() // permits the thread to execute independently from the thread handle 
// detaches our std:: thread variable from executing entity, now our entity lives its own life. std::thread variable may be removed while the entity keeps alive 

joinable() // checks whether the thread is joinable, i.e. potentially running in parallel context 
// if thread is attached to something which is executing now, it returns true, otherwise false 

這裏是一些代碼示例,將清除出你的誤解:

#include <iostream> 
#include <thread> 
#include <chrono> 

using namespace::std; 

void some_func1() { 
    cout << "some_func1 thread started " << endl; 
    this_thread::sleep_for(chrono::seconds(2)); 
    cout << "some_func1 thread finished " << endl; 
} 

void some_func2() { 
    cout << "some_func2 thread started " << endl; 
    this_thread::sleep_for(chrono::seconds(2)); 
    cout << "some_func2 thread finished " << endl; 
} 


int main() {  

    thread some_thread; 

    cout << "Is some_thread joinable: " << some_thread.joinable() << endl; 

    some_thread = thread(some_func1); 

    cout << "Is some_thread joinable: " << some_thread.joinable() << endl; 

    some_thread.detach(); 

    cout << "Is some_thread joinable: " << some_thread.joinable() << endl; 

    this_thread::sleep_for(chrono::seconds(1)); 

    some_thread = thread(some_func2); 

    cout << "Is some_thread joinable: " << some_thread.joinable() << endl; 

    some_thread.join(); 

    cout << "Is some_thread joinable: " << some_thread.joinable() << endl; 
} 

// Output is: 
// Is some_thread joinable: 0 
// some_func1 thread started 
// Is some_thread joinable: 1 
// Is some_thread joinable: 0 
// some_func2 thread started 
// Is some_thread joinable: 1 
// some_func1 thread finished 
// some_func2 thread finished 
// Is some_thread joinable: 0 
// Press any key to continue . . . 

如果你想確保,你的實體執行完畢的線程變量刪除之前,你可以把它包在另一個類中,並在析構函數中調用join(),正如你提到的那樣。

或者你也可能把它包裝在另一個將在析構函數中調用detach()

這兩種方式可以防止你大量的粉碎。

#include <iostream> 
#include <thread> 
#include <chrono> 

using namespace std; 


typedef void Myfunc(); 

void some_func1() { 
    cout << "some_func1 thread started " << endl; 
    this_thread::sleep_for(chrono::seconds(2)); 
    cout << "some_func1 thread finished " << endl; 
} 

void some_func2() { 
    cout << "some_func2 thread started " << endl; 
    this_thread::sleep_for(chrono::seconds(2)); 
    cout << "some_func2 thread finished " << endl; 
} 

class ICareAboutThread { 
    std::thread thread_; 
public: 
    ICareAboutThread(Myfunc f = nullptr) : thread_(f) {}; 
    ~ICareAboutThread() { join(); } 
    bool joinable() { return thread_.joinable();} 
    void join() { thread_.join();} 
    void detach() { thread_.detach();} 

    // other constructors : move , safe copying - if necessary; 
}; 


class IDontCareAboutThread { 
    std::thread thread_; 
public: 
    IDontCareAboutThread(Myfunc f = nullptr) : thread_(f) {}; 
    ~IDontCareAboutThread() { detach(); } 
    bool joinable() { return thread_.joinable(); } 
    void join() { thread_.join(); } 
    void detach() { thread_.detach(); } 

    // other constructors : move , safe copying - if necessary; 
}; 

int main() {  

    ICareAboutThread i_care(some_func1); 

    this_thread::sleep_for(chrono::seconds(1)); 

    IDontCareAboutThread i_dont_care(some_func2); 

    return 0; 
} 

// Output is: 
// some_func1 thread started 
// some_func2 thread started 
// some_func1 thread finished 
// Press any key to continue . . . 

現在我希望它的晶瑩剔透你,如果你瞭解當變量刪除:d

相關問題