类的动态分配

Dynamic allocation of classes

本文关键字:动态分配      更新时间:2023-10-16

我有一个关于对象数组分配的问题, 问题是这样的: 我有一个名为 person 的类:

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* 名称中的分配字符串,但是当我添加析构函数时,它会在循环结束后立即触发, 每个被创造的人都会立即被摧毁, 我知道可以制作一个指针数组并分配人员,但是在这个任务中,我应该这样做, 有没有一种正确的方法可以在不立即触发析构函数的情况下做到这一点?

在这一行:

pArr[j] = Person(Name, id);

您正在创建一个临时Person对象,然后将其分配给pArr[j]对象。Person没有定义显式复制赋值运算符,因此编译器会自动生成一个运算符,它只是执行值从一个对象到另一个对象的成员逐个成员复制。

当临时;超出范围时,它会自动销毁。 编译器生成的赋值运算符将name指针按原样复制到pArr[j]对象,因此,如果Person具有释放其name的析构函数,则pArr[j]对象将留下一个悬空的name指向释放内存的指针。

您的Person类不遵循三法则:

三法则(也称为三巨头

法则或三巨头法则(是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符合三法则并且可以正确复制:

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