C++ 如何为类并集类编写析构函数

C++ 如何为类并集类编写析构函数,c++,c++11,memory-management,destructor,unions,C++,C++11,Memory Management,Destructor,Unions,我试图使用一个具有一些非基本变量的联合(C++),但我一直在尝试为该类创建析构函数。正如我所读到的,不可能猜测使用的是union的哪个变量,因此没有隐式析构函数,并且当我在堆栈上使用此union时,编译器会错误地提示删除了析构函数。工会成员如下: struct LuaVariant { LuaVariant() : type(VARIANT_NONE) { } LuaVariantType_t type; union { std::string text

我试图使用一个具有一些非基本变量的联合(C++),但我一直在尝试为该类创建析构函数。正如我所读到的,不可能猜测使用的是union的哪个变量,因此没有隐式析构函数,并且当我在堆栈上使用此union时,编译器会错误地提示删除了析构函数。工会成员如下:

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

    LuaVariantType_t type;
    union {
        std::string text;
        Position pos;
        uint32_t number;
    };
};
type
变量保存正在使用的联合字段(从枚举中选择),用于从联合中读取数据,并可用于猜测应删除的值。我尝试了一些不同的方法,但没有一种有效。首先,刚刚尝试了默认析构函数:

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

但由于我不是联合的大师,我不知道这是否会导致其他问题,比如分配的内存永远不会被释放,或者类似的问题。这种交换策略可以在没有缺陷和问题的情况下使用吗?

如果您想在C++11中的联合中使用
std::string
,您必须显式调用它的析构函数,并放置新的位置来构造它。示例来自:

#包括
#包括
#包括
联盟S{
std::字符串str;
std::vec;
~S(){}//需要知道哪个成员处于活动状态,只能在类union中使用
}; // 整个并集占用max(sizeof(string)、sizeof(vector))
int main()
{
S={“你好,世界”};
//此时,s.vec的读数为UB
std::cout此分组(用于区分类型的并集+枚举值)称为区分并集

调用任何构造/销毁都将取决于您,因为联合本身不能(如果可以,它还可以在联合内区分初始化/未初始化类型,并且您不需要枚举)

代码:


很好,但这是一个很大的麻烦。有时我不知道正在使用哪个字段(我只是推拉Lua堆栈),所以我需要一个开关来销毁它们,对吗?还有,我的方法有什么缺点吗?@ranisalt你必须知道你在使用哪个字段,知道你可以访问哪个字段。访问活动字段以外的任何其他字段都是UB。你需要显式调用析构函数,而不是使用交换技巧。你的代码不会调用析构函数rs表示联合中的对象。这可能只是资源泄漏,而不是UB,但最干净和正确的解决方案是调用析构函数。类联合类是
联合
,或包含匿名联合的类/结构的标准术语。我需要在联合中添加一个空析构函数以使其工作。我是否缺少something?我有一个“value::~value()是一个已删除的函数”,否则
#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>();
}
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;
};