如何为类似union的类编写析构函数

时间:2015-07-29 03:16:11

标签: c++ c++11 memory-management destructor unions

我试图使用具有一些非原始变量的联合(C ++),但是我试图为该类创建析构函数。正如我所读到的那样,无法猜测正在使用联合的哪个变量,因此没有隐式析构函数,并且因为我在堆栈上使用此联合,所以编译器错误会删除析构函数。工会如下:

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

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

type变量保存正在使用的union的哪个字段(从枚举中选择),以便从union中读取,并且可以用来猜测应该删除哪个值。我尝试了一些不同的方法,但没有一个工作。首先,只是尝试了默认的析构函数:

~LuaVariant() = default;

它不起作用,因为默认是...已删除。因此,我尝试将值换成空值,这样内容就会被删除,并且没有问题"泄漏"空值:

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

但由于我不是工会大师,我不知道这是否会导致其他问题,例如分配的内存永远不会被解除分配,或类似的东西。这种交换策略能否在没有缺陷和问题的情况下使用?

2 个答案:

答案 0 :(得分:9)

此分组(用于区分类型的union + enum值)称为区分联合。

由你来调用任何构造/破坏,因为联盟本身不能(如果可以的话,它也能够区分联盟内的初始化/非初始化类型,你不需要枚举)。

代码:

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

答案 1 :(得分:3)

如果要在C ++ 11中的联合中使用 aP.controller('skillsCtrl', ['$scope', function ($scope) { $scope.oneSkills = ["HTML", "CSS", "Sass", "Javascript", "Jquery", "AngularJS"]; $scope.twoSkills = ["Grunt", "Node", "Ruby on Rails","Adobe Photoshop", "Adobe Illustrator"]; }]); ,则必须显式调用其析构函数,并使用new来构造它。 cppreference.com的示例:

std::string