2012-12-08 106 views
0

在許多情況下,我看到這種情況在pthread_create混亂

class Foo 
{ 
    static void* ThreadFun(void* p) 
    { 
     Derived* args = (Derived*)p; 

     //do something with args. 
     //example 
     //cout << args->getname(); 
    } 

    void function() 
    { 
     Base* args = new Derived(); 
     args->setname("test"); 

     pthread_t id; 
     int ret = pthread_create(&id, NULL, ThreadFun, (void*) args);  
    } 
} 

首先,是正確的C++代碼?或者我錯過了什麼?我做了一些閱讀,顯然將類的指針投射到void *會導致信息的丟失,並且在派生類上調用getname()可能是非法的。

他們認爲如果我理解正確的是這樣的:

void function() 
{ 
    Base* args = new Derived(); 
    args->setname("test"); 

    void* pargs = (Base*)malloc(sizeof(*args)); // to be freed in ThreadFun 
    pargs = args; 
    pthread_t id; 
    int ret = pthread_create(&id, NULL, ThreadFun, pargs);  
} 

我不明白這一點真的,我怎麼需要這正常嗎?

+0

第一個肯定比較好,第二個是完全的災難。 – goji

+0

是什麼意思?... – Kam

+0

使用malloc分配內存塊的目的是什麼,然後通過執行pargs = args完全丟失內存塊?指向內存(pargs)的點是你分配內存的唯一鏈接,現在已經丟失了。它現在指向分配給新操作員的內存。 – goji

回答

3

哦,哇......不,你的第二個例子泄露了malloc()分配的內存,如果你遵循這個建議,你將在ThreadFun中免費分配你的new Derived()分配你認爲你正在釋放malloc()分配。

關於鑄造一個指向類的指針void *造成信息的丟失....它沒有。簡單的&簡單。它失去了編譯器對這個指針意味着什麼的理解。如果知道這意味着什麼,你總是可以將它恢復到正確的類型&獲得它的全部功能,這正是第一個例子所做的。當ThreadFun()函數在新線程中啓動時,它會將void *轉換回原來的類型,即Derived *。

我注意到,當您最初調用new Derived()分配時,您將返回指針指定給類型爲Base*的指針。我假定繼承自class Base,所以在那裏的賦值實際上會導致「信息丟失」,從一個Base*類型的指針中,您將失去Derived類的非多態行爲。但是當你把它轉換回它在ThreadFun()中的真實類型時,它恢復了它的全部功能。請注意,如果您改爲使用new Base對象並啓動了新線程,並且在ThreadFun()中將其轉換爲Derived*,編譯器會讓您這樣做,但您會遇到未定義的行爲...可能是崩潰。因爲(由於pthreads接口)你必須通過一個void *,所以沒有類型檢查的安全性,即使是C++風格的轉換。所以你可以將void *轉換爲你想要的任何東西,編譯器會讓你。但是,當然唯一真正有效的演員陣容是(Base*)(Derived*),或者它們之間的任何東西在繼承層次結構中。

我還應該提到,作爲一個void *,你不能刪除這個對象並讓它的析構函數運行。要刪除該對象,您需要將該指針轉換回它的任何類型,以便編譯器知道要調用哪個析構函數。還有一個棘手的棘手的情況,你可以得到與指針Derived類是Base*型....如果Base::~Base()析構函數不是virtual,如果你調用一個Base*該對象delete刪除您Derived對象,分配會完全釋放,但只有對象的Base部分都會有其析構函數運行.....除非析構函數都與virtual關鍵字,它可以讓你只用Base*它甚至刪除Derived對象定義。我是否讓自己完全不清楚?

+0

謝謝!正是我正在尋找的東西,特別是關於信息完整性的部分, – Kam