我有一个关于对象数组分配的问题, 问题是这样的: 我有一个叫做人的课:
class Person {
char* name;
int ID;
public:
Person(char* name = NULL, int ID = 0) :name(name), ID(ID) {};
}
我正试图让一群人像这样:
Person *pArr = new Person[size];
然后我从文件中提取数据(char *表示字符串,int表示ID) 我使用for循环和构造函数将人放在循环中,如下所示:
for (int j = 0; j < size3; j++) {
pArr[j] = Person(Name, id);
}
完成程序后,我想使用析构函数并释放存储在char *名称中的已分配字符串,但是当我添加析构函数时,它会在循环结束后立即触发, 正在创建的每个人都会被立即销毁, 我知道它可以制作一个指针数组并分配给那个人,但是在这个任务中,我想这样做, 有没有正确的方法来做到这一点,而不是立即触发析构函数?
答案 0 :(得分:6)
在这一行:
pArr[j] = Person(Name, id);
您正在创建临时 Person
对象,然后将其分配给pArr[j]
对象。 Person
没有定义明确的复制赋值运算符,因此编译器会自动为您生成一个,它只是执行从一个对象到另一个对象的逐个成员的值复制。
当临时超出;
的范围时,它会自动销毁。编译器生成的赋值运算符按原样将name
指针复制到pArr[j]
对象,因此如果Person
具有释放其name
的析构函数,则pArr[j]
对象将留下一个悬空的name
指向释放内存的指针。
您的Person
课程未遵循Rule of Three:
三规则(也称为三巨头或三巨头的规则)是C ++(在C ++ 11之前)的经验法则,声称如果一个类定义了一个(或更多)以下它应该明确定义所有三个:
- 析
- 复制构造函数
- 复制分配操作员
由于您希望Person
具有释放name
的析构函数,因此它还需要一个复制构造函数和一个复制赋值运算符,以便它可以为析构函数复制name
以释放,例如:
class Person
{
char* name;
int id;
public:
Person(const char* Name = NULL, int ID = 0)
: name(new char[std::strlen(Name)+1]), id(ID)
{
std::strcpy(name, Name);
}
Person(const Person &src)
: name(new char[std::strlen(src.name)+1]), id(src.id)
{
std::strcpy(name, src.name);
}
~Person()
{
delete[] name;
}
Person& operator=(const Person &rhs)
{
if (&rhs != this)
{
Person tmp(rhs);
//std::swap(tmp.name, name);
char *p = tmp.name;
tmp.name = name;
name = p;
id = tmp.id;
}
return *this;
}
};
现在,回到这一行:
pArr[j] = Person(Name, id);
临时将安全正确地复制到pArr[j]
。请注意,如果您事先动态分配Name
,则现在必须将其释放,因为Person
会自行创建内部副本。
如果您可以将char*
更改为std::string
,那么您不必担心编译器会生成默认副本,因为std::string
符合规则3并且将是正确复制:
class Person
{
std::string name;
int id;
public:
Person(const std::string &name = std::string(), int ID = 0)
: name(name), id(ID)
{
}
// no explicit copy constructor, destructor, or
// assignment operator is needed, as compiler-generated
// defaults will suffice...
};