Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

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 guess what variable of the union is being used so there is no implicit destructor, and as I'm using this union on the stack, the compiler errors that the destructor is deleted. The union is as follows:

struct LuaVariant {
    LuaVariant() : type(VARIANT_NONE) { }

    LuaVariantType_t type;
    union {
        std::string text;
        Position pos;
        uint32_t number;
    };
};

The type variable holds what field of the union is being used (chosen from an enum), for the purpose of reading from the union and it could be used to guess what value should be deleted. I tried some different approaches but none of them worked. First of all, just tried the default destructor:

~LuaVariant() = default;

It did not work, as the default is... deleted. So, I tried swapping the value with an empty one, so that the contents would be erased and there would be no problem "leaking" an empty value:

~LuaVariant() {
    switch (type) {
        case VARIANT_POSITION:
        case VARIANT_TARGETPOSITION: {
            Position p;
            std::swap(p, pos);
            break;
        }
        case VARIANT_STRING: {
            std::string s;
            std::swap(s, text);
            break;
        }
        default:
            number = 0;
            break;
    }
};

But as I am not a master of the unions, I don't know if that can cause other problems, such as allocated memory that never gets deallocated, or something like that. Can this swap strategy be used without flaws and issues?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
873 views
Welcome To Ask or Share your Answers For Others

1 Answer

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;
};

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
...