4

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

// 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 包含有效的内存位置,为什么?)。

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

同样,如果我的类包含联合成员(如何为包含联合的类编写析构函数),如何破坏类对象?

4

4 回答 4

3

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

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

另外 - 你的数组太小了。size()返回字符数,但如果您使用char*字符串类型,则需要为空字符 ( \0) 留出空间来处理终止。

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

于 2013-04-18T10:20:15.753 回答
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 中)的规则:

实施它们。

于 2013-04-18T09:54:34.280 回答
1

您不尊重新删除配对:new与配对delete,与new[]配对delete[]。你在做new[],但在打电话delete;这是不相容的。

附带说明一下,构造函数存在内存泄漏:szName一旦该指针被分配给szJobTitle) 所覆盖,分配给的内存就永远不会释放。

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

于 2013-04-18T09:55:58.483 回答
1

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

我没有编译器(或没有时间编译您的代码),但是(除了Nawaz 解决的问题)我猜这是因为您将工会成员视为类成员。在您的联合中,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 中,因此会发生内存泄漏。&szJobTitle 使用与 &szName 相同的内存位置,因此使用第 (1) 行中的分配,您会丢失在 szName 中分配的地址。如果 szName 和 szJobTitle 属于不同类型(内存占用不匹配),设置 szJobTitle 也会损坏(或仅部分覆盖 szTitle)。

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

我认为您没有足够的细节来实现析构函数。查看C++ 中可区分联合的概念,了解如何正确实现这一点。通常你的联合成员应该管理他们自己的内存(使用 std::string,而不是 char*),然后你的析构函数只会删除分配的内容(但你必须显式调用它)。

同样,如果我的类包含联合成员,如何破坏类对象(如何为包括联合的类编写析构函数)?

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

于 2013-04-18T10:23:59.090 回答