How to write destructor for union-like class

前端 未结 2 1158
一生所求
一生所求 2020-12-19 07:04

I\'m trying to use an union (C++) that has some non-primitive variables, but I\'m stuck trying to create the destructor for that class. As I have read, it is not possible to

相关标签:
2条回答
  • 2020-12-19 07:37

    If you want to use std::string in a union in C++11, you have to explicitly call its destructor, and placement new to construct it. Example from cppreference.com:

    #include <iostream>
    #include <string>
    #include <vector>
    union S {
        std::string str;
        std::vector<int> vec;
        ~S() {} // needs to know which member is active, only possible in union-like class 
    }; // the whole union occupies max(sizeof(string), sizeof(vector<int>))
    
    int main()
    {
        S s = {"Hello, world"};
        // at this point, reading from s.vec is UB
        std::cout << "s.str = " << s.str << '\n';
        s.str.~basic_string<char>();
        new (&s.vec) std::vector<int>;
        // now, s.vec is the active member of the union
        s.vec.push_back(10);
        std::cout << s.vec.size() << '\n';
        s.vec.~vector<int>();
    }
    
    0 讨论(0)
  • 2020-12-19 07:51

    This grouping (union + enum value for discriminating type) is called a discriminated union.

    It will be up to you to call any construction/destruction, because the union itself cannot (if it could, it would also be able to discriminate for initialized/non-initialized types within the union, and you would not need the enum).

    Code:

    class LuaVariant // no public access to the raw union
    {
    public:
        LuaVariant() : type(VARIANT_NONE) { }
        ~LuaVariant() { destroy_value(); }
    
        void text(std::string value) // here's a setter example
        {
            using std::string;
            destroy_value();
            type = VARIANT_TEXT;
            new (&value.text) string{ std::move(value) };
        }
    private:
    
        void destroy_value()
        {
            using std::string;
            switch(type)
            {
            case VARIANT_TEXT:
                (&value.text)->string::~string(); 
                break;
            case VARIANT_POSITION:
                (&value.pos)->Position::~Position(); 
                break;
            case VARIANT_NUMBER:
                value.number = 0;
                break;
            default:
                break;
            }
        }
    
        LuaVariantType_t type;
        union {
            std::string text;
            Position pos;
            uint32_t number;
        } value;
    };
    
    0 讨论(0)
提交回复
热议问题