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),如何破坏一个类对象?
答案 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)
您不尊重新删除配对:new
与delete
对,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的哪些成员被设置。