2016-02-25 62 views
3

我創建了一個使用聯盟作爲其字段的結構。這裏是一個小的代碼示例:分配聯盟的字段

#include <iostream> 
#include <string> 

enum Type 
{ 
    STR, 
    INT 
}; 

struct MyStruct 
{ 
    Type type; 
    union Value 
    { 
     std::string str; 
     int i; 
     Value(){} 
     ~Value(){}; 

    } value; 
    void setType(Type type) 
    { 
     this->type = type; 
    } 
    void setValue(const std::string& data) 
    { 
     this->value.str = data; 
    } 
    MyStruct(){} 
    ~MyStruct(){} 
}; 

int main() 
{ 
    MyStruct my; 
    my.setType(Type::STR); 
    my.setValue("Hallo"); 

    std::cout << my.value.str << std::endl; 

    return 0; 
} 

設置值,我得到一個錯誤(分段故障(核心轉儲))什麼是這樣做的正確方法?謝謝!

+1

將int與一個字符串聯合起來是個可怕的想法。 – user3528438

+1

你的'union'可能有一個數據成員,它有一個非平凡的特殊成員函數。請參閱:[鏈接](http://en.cppreference.com/w/cpp/language/union) – knivil

+3

您不應該有單獨的'setType'和'setValue'函數,而應該一次性設置(因爲您需要檢查現有類型以瞭解是否需要調用構造函數和析構函數)。你最好查看如何使用包含字符串的聯合的示例代碼,而不是猜測/發佈問題。 –

回答

6

要小心。工會中的非POD類型正在尋求麻煩。說這個,在C++ 11中得到支持,只提供給最初的一個成員。這意味着你必須改變工作方式。

中平凡,來修復你的程序,因爲它現在代表,您只需使用放置新:

void setValue(const std::string& data) 
{ 
    new (&value.str) std::string(data); 
} 

但現在,如果你想要一個不同成員以後設置,您就需要使用位置刪除字符串。要做到這一點,你需要知道在那裏有一個字符串。因此,您無法輕鬆將setValuesetType分開。

一個選項(不是特別漂亮)是:

private: 
    void setType(type) { 
     // Destruct existing type 
     switch(this->type) { 
     case STR: 
      value.str.~std::string(); 
      break; 
     default:; 
     } 

     this->type = type; 
    } 

public: 
    void setValue(const std::string& data) 
    { 
     setType(STR); 
     new (&value.str) std::string(data); 
    } 

    void setValue(int data) 
    { 
     setType(INT); 
     value.i = data; 
    } 

而且不要忘了在~MyStruct妥善銷燬價值。

+0

在未構造的字符串對象上調用字符串析構函數可能會有問題。或者什麼是類型的初始值? – knivil

+0

嗯,是的,我沒有提到,但應該有。很明顯,'type'的初始值應該是明智的。我會考慮選擇'NO_TYPE'的'默認'枚舉。或者將其設置爲「INT」,值爲零。 – paddy

+0

我的觀點:可能'this-> type'在默認構造對象上爲零,如示例代碼中所示。如果你使用'setValue'指定一個字符串對象,那麼析構函數將在一個未初始化/未構造的字符串對象上被調用。是的,在默認的構造函數中處理這個問題會很好,「NO_TYPE」沒問題。 – knivil

4

儘管C++ 11確實允許您在聯合中使用類,但它通常被認爲是不好的做法,因爲它是未定義行爲的雷區。

如果你的聯盟的構造函數不構造類實例的聯合成員 - 就​​像你的示例代碼一樣 - 根據定義,類實例永遠不會被構造。

您的代碼然後嘗試使用聯合的類成員。即其運營商=。因爲這個類實例還沒有被構造,所以這變成了未定義的行爲,這會導致你的崩潰。

堅持與POD s在您的工會。不那麼悲傷。

+0

由於使用了術語,這是有點令人困惑的。你大概說,工會的'str'成員需要建造,是嗎? _「工會的類實例」這樣的短語在這種情況下非常模糊。你能整理一下答案嗎? –

+1

在一個工會中,這當然是可能的。畢竟,這就是工會的意思。嘗試在調試器中加載示例代碼,逐步添加代碼,並親自看看std :: string的構造函數在這裏不會被調用。歡迎來到C++。 –

+0

是的,我已經編輯了我的評論 - 以爲你指的是班級成員,而不是工會成員。因爲,那就是你最初所說的:)(雖然聯合是一種類)_「歡迎來到C++」_不知道是否開玩笑或拖動,但我一直在使用C++很長一段時間! –