C ++:Union Destructor

时间:2013-04-18 09:51:37

标签: c++ destructor unions

union是用户定义的数据或类类型,在任何给定时间,它只包含其成员列表中的一个对象。假设需要动态分配所有可能的候选成员。对于例如。

// Union Destructor
#include <string>
using namespace std;

union Person
{
private:
    char* szName;
    char* szJobTitle;
public:
    Person() : szName (nullptr), szJobTitle (nullptr) {}
    Person (const string& strName, const string& strJob)
    {
        szName = new char[strName.size()];
        strcpy (szName, strName.c_str());

        szJobTitle = new char [strJob.size()];
        strcpy (szJobTitle, strJob.c_str());    // obvious, both fields points at same location i.e. szJobTitle
    }
    ~Person()   // Visual Studio 2010 shows that both szName and szJobTitle
    {           // points to same location.
        if (szName) {
            delete[] szName;     // Program crashes here.
            szName = nullptr;  // to avoid deleting already deleted location(!)
        }
        if (szJobTitle)
            delete[] szJobTitle;
    }
};

int main()
{
    Person you ("your_name", "your_jobTitle");
    return 0;
}

上面的程序在~Person中的第一个删除语句中崩溃(当szName包含有效的内存位置时,为什么?)。

析构函数的正确实现是什么?

同样,如果我的类包含一个union成员(how to wrtie destructor for class including a Union),如何破坏一个类对象?

4 个答案:

答案 0 :(得分:4)

您一次只能使用一个union的成员,因为它们共享相同的内存。但是,在构造函数中,您初始化两个成员,它们会相互覆盖,然后在析构函数中最终释放它两次。您正在尝试使用它,就好像它是一个结构(基于您需要使用结构的字段的名称)。

然而,如果你需要一个联合,那么你可能需要一个结构作为一种信封,它有一些代表正在使用的成员的id,以及一个构造函数和一个处理资源的析构函数。

另外 - 你的阵列太小了。 size()返回字符数,但如果使用char*作为字符串类型,则需要空格以使空字符(\0)处理终止。

如果您需要工会,请尝试使用Boost.Variant。它比普通的工会更容易使用。

答案 1 :(得分:2)

当您使用delete时,您正在使用delete [],因为您使用的是new [],而不是new

更改这些:

delete szName;
delete szJobTitle;

到这些:

delete [] szName;
delete [] szJobTitle;

顺便说一下,析构函数中的if条件是没有意义的。我的意思是,如果指针是nullptr,则可以安全地编写delete ptr;,即

A *ptr = nullptr;
delete ptr; //Okay! No need to ensure ptr is non-null

除此之外,你违反了三条规则(或五条,在C​​ ++ 11中):

实施它们。

答案 2 :(得分:1)

您不尊重新删除配对:newdelete对,new[]delete[]配对。您正在new[],但是正在呼叫delete;这是不相容的。

作为旁注,构造函数有一个内存泄漏:一旦指针被赋值给szName覆盖,分配给szJobTitle的内存就不会被释放。

由于这是C ++,您通常应该使用std::string而不是char*来表示字符串。

答案 3 :(得分:1)

  

上面的程序在~Person中的第一个删除语句中崩溃(当szName包含有效的内存位置时,为什么?)。

我没有编译器(或编译代码的时间)但是(除the problems addressed by Nawaz之外)我猜它是因为你将union成员视为类成员。在你的联盟中,szName和szJobTitle应该看起来像两个具有相同地址的变量:

Person (const string& strName, const string& strJob)
{
    szName = new char[strName.size()];
    strcpy (szName, strName.c_str());

    szJobTitle = new char [strJob.size()]; // this creates memory leak (1)
    strcpy (szJobTitle, strJob.c_str());
}

由于您分配了新内存并将其放在szJobTitle中,因此会出现内存泄漏。 &amp; szJobTitle使用与&amp; szName相同的内存位置,因此使用第(1)行中的赋值可以松开在szName中分配的地址。如果szName和szJobTitle属于不同类型(具有不匹配的内存占用),则设置szJobTitle也会损坏(或仅部分覆盖szTitle)。

  

析构函数的正确实现是什么?

我认为你没有足够的细节来实现析构函数。查看discriminated unions in C++的概念,了解如何正确实现此功能。通常你的联盟成员应该管理自己的内存(使用std :: string,而不是char *)然后你的析构函数只会删除已分配的内容(但你必须明确地调用它)。

  

同样,如果我的类包含一个union成员,如何破坏一个类对象(如何为类包含一个Union的wrtie析构函数)?

再次,看看有歧视的工会。它基本上是union和enum的关联,其中枚举映射到union的成员,并设置为指定union的哪些成员被设置。