动态分配类

Ale*_*x K 1 c++ arrays class

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

class Person {
    char* name;
    int ID;


public:
    Person(char* name = NULL, int ID = 0) :name(name), ID(ID) {};
}
Run Code Online (Sandbox Code Playgroud)

而我正试图让一群人像这样:

Person *pArr = new Person[size];
Run Code Online (Sandbox Code Playgroud)

之后我从文件中提取数据(char*表示字符串,int表示ID),我使用for循环和构造函数将这些人放在循环中,如下所示:

for (int j = 0; j < size3; j++) {
pArr[j] = Person(Name, id);
}
Run Code Online (Sandbox Code Playgroud)

我完成程序之后,我想使用析构函数并释放存储在char*名称中的已分配字符串,但是当我添加析构函数时,它会在循环结束后立即触发,每个正在创建的Person都会被立即销毁,我知道它可以创建一个指针数组并分配给那个人,但是在这个赋值中我想这样做,是否有正确的方法来做到这一点而不立即触发析构函数?

Rem*_*eau 6

在这一行:

pArr[j] = Person(Name, id);
Run Code Online (Sandbox Code Playgroud)

您正在创建一个临时 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;
    }
};
Run Code Online (Sandbox Code Playgroud)

现在,回到这一行:

pArr[j] = Person(Name, id);
Run Code Online (Sandbox Code Playgroud)

临时将被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...
};
Run Code Online (Sandbox Code Playgroud)