当动态创建一个包含另一个动态创建的结构数组的结构数组时,内存管理

Memory management when dynamically creating an array of structs that contain another dynamically created array of structs

本文关键字:数组 结构 创建 动态 内存 管理 包含 一个 另一个      更新时间:2023-10-16

我正在尝试了解与动态结构数组内部的动态结构数组相关的内存问题。我正在动态创建一系列结构,并将其附加到变量"人"上,然后动态创建结构数组,并将其连接到每个"人"对象的内部变量"宠物"。一个简单的例子是:

typedef struct {
  int age;
} Pet;
typedef struct {
  Pet *pets;
} Person

创建2个对象人员阵列并将其连接到可变的"人"

persons = (Person*) ::operator new(sizeof(Person) * 2);
persons[0]
persons[1]

创建3个对象宠物数组,然后将其连接到"人"

的对象#1的变量"宠物"
persons[0].pets = (Pet*) ::operator new(sizeof(Pet) * 3);
persons[0].pets[0].age
persons[0].pets[1].age
persons[0].pets[2].age

创建2个对象pet数组,然后将其连接到"人"

的对象2的变量"宠物"
persons[1].pets = (Pet*) ::operator new(sizeof(Pet) * 2);
persons[1].pets[0].age
persons[1].pets[1].age

如果我动态创建另一个结构数组并将其连接到"人"数组,以前将数组附加到变量"人"中?

创建4个对象人员阵列,并将其连接到变量的" persons",以替换前两个对象数组。

persons = (Person*) ::operator new(sizeof(Person) * 4);
persons[0]
persons[1]
persons[2]
persons[3]

如果没有,我需要释放"人"数组每个对象的每个"宠物"阵列?

这里是在Arduino上运行的代码中。该代码工作正常,似乎无限地重复没有任何打ic,但这并不意味着它是合法的。

// DYNAMIC MEMORY
// OBJECTS
// Pet object
typedef struct {
  char *name;
  int age;
} Pet;
// Person object
typedef struct {
  char *name;
  int age;
  int numberOfPets;
  Pet *pets;          // OBJECT 'Pet' is part of OBJECT 'Person'
} Person;
#define OBJECT_PET    0
#define OBJECT_PERSON 1

// DYNAMIC MEMORY HANDLING
// ARRAY Creation
void* createArray(int numberOfObjects, int typeOfObject) {
  numberOfObjects;
  int memorySize;
  switch (typeOfObject) {
    case OBJECT_PET:
      Serial.print("Creating Pet array of ");
      memorySize = sizeof(Pet) * numberOfObjects;
      break;
    case OBJECT_PERSON:
      Serial.print("Creating Person array of ");
      memorySize = sizeof(Person) * numberOfObjects;
      break;
  }
  Serial.print(numberOfObjects);
  Serial.println(" objects");
  return ::operator new(memorySize);
}
// GLOBAL VARIABLES
Person *persons;
int numberOfPersons;
void createPersonsAndPetsFirst() {
  numberOfPersons = 3;
  // CREATE 3 empty Person objects [0, 1, 2]
  persons = (Person*) createArray(numberOfPersons, OBJECT_PERSON);
  // ENTER Specific Person information for Person #1
  // Person #1 [0]
  persons[0].name = "Larry";
  persons[0].age = 19;
  persons[0].numberOfPets = 2;
  // CREATE 2 empty Pet objects for Person #1
  persons[0].pets = (Pet*) createArray(persons[0].numberOfPets, OBJECT_PET);
  // ENTER Specific Pet information for Pet #1
  // Pet #1
  persons[0].pets[0].name = "Xander";
  persons[0].pets[0].age = 3;
  // ENTER Specific Pet information for Pet #2
  // Pet #2
  persons[0].pets[1].name = "Shorty";
  persons[0].pets[1].age = 6;
  // ENTER Specific Person information for Person #2
  // Persons #2 [1]
  persons[1].name = "Mark";
  persons[1].age = 29;
  persons[1].numberOfPets = 1;
  // CREATE 1 empty Pet object for Person #2
  persons[1].pets = (Pet*) createArray(persons[1].numberOfPets, OBJECT_PET);
  // ENTER Specific Pet information for Pet #1
  // Pet #1 [0]
  persons[1].pets[0].name = "Fido";
  persons[1].pets[0].age = 5;
  // ENTER Specific Person information for Person #3
  // Person #3 [2]
  persons[2].name = "Larry";
  persons[2].age = 19;
  persons[2].numberOfPets = 2;
  // CREATE 2 empty Pet objects for Person #1
  persons[2].pets = (Pet*) createArray(persons[0].numberOfPets, OBJECT_PET);
  // ENTER Specific Pet information for Pet #1
  // Pet #1
  persons[2].pets[0].name = "Nado";
  persons[2].pets[0].age = 12;
  // ENTER Specific Pet information for Pet #2
  // Pet #2
  persons[2].pets[1].name = "Buster";
  persons[2].pets[1].age = 4;
  Serial.println();
}
void createPersonsAndPetsSecond() {
  numberOfPersons = 2;
  // CREATE 2 empty Person objects [0, 1]
  persons = (Person*) createArray(numberOfPersons, OBJECT_PERSON);
  // ENTER Specific Person information for Person #1
  // Person #1 [0]
  persons[0].name = "Chad";
  persons[0].age = 22;
  persons[0].numberOfPets = 1;
  // CREATE 1 empty Pet object for Person #1
  persons[0].pets = (Pet*) createArray(persons[0].numberOfPets, OBJECT_PET);
  // ENTER Specific Pet information for Pet #1
  // Pet #1
  persons[0].pets[0].name = "Lucky";
  persons[0].pets[0].age = 5;
  // ENTER Specific Person information for Person #2
  // Persons #2 [1]
  persons[1].name = "Lisa";
  persons[1].age = 36;
  persons[1].numberOfPets = 2;
  // CREATE 2 empty Pet objects for Person #2
  persons[1].pets = (Pet*) createArray(persons[1].numberOfPets, OBJECT_PET);
  // ENTER Specific Pet information for Pet #1
  // Pet #1 [0]
  persons[1].pets[0].name = "Chester";
  persons[1].pets[0].age = 7;
  // ENTER Specific Pet information for Pet #2
  // Pet #2 [1]
  persons[1].pets[1].name = "Marlo";
  persons[1].pets[1].age = 12;
  Serial.println();
}
void sendPersonsAndPetsInformationToHost() {
  Serial.print("Number of Persons = ");
  Serial.println(numberOfPersons);
  for (int personsIndex = 0; personsIndex < numberOfPersons; personsIndex++) {
    // SHOW Person
    Serial.print("Person #");
    Serial.print(personsIndex + 1);
    Serial.println(" Information");
    // SHOW Person Information
    Serial.print("Name = ");
    Serial.println(persons[personsIndex].name);
    Serial.print("Age  = ");
    Serial.println(persons[personsIndex].age);
    // SHOW Person number of Pets Information
    Serial.print("Number of Pets = ");
    Serial.println(persons[personsIndex].numberOfPets);
    for (int petsIndex = 0; petsIndex < persons[personsIndex].numberOfPets; petsIndex++) {
      // SHOW Pet
      Serial.print("Pet #");
      Serial.print(petsIndex + 1);
      Serial.println(" Information");
      Serial.print("Name = ");
      Serial.println(persons[personsIndex].pets[petsIndex].name);
      Serial.print("Age  = ");
      Serial.println(persons[personsIndex].pets[petsIndex].age);
    }
    Serial.println();
  }
}

void setup() {
  // OPEN Serial communication
  Serial.begin(115200);
}
void loop() {
  // CREATE First Persons and Pets Arrays
  createPersonsAndPetsFirst();
  // SEND Persons and Pets array information to Host
  sendPersonsAndPetsInformationToHost();
  delay(2000);
  // CREATE Second Persons and Pets Arrays
  createPersonsAndPetsSecond();
  // SEND Persons and Pets array information to Host
  sendPersonsAndPetsInformationToHost();
  delay(2000); 
}

no 先前分配的内存将不会被释放。您将失去所有分配的内存。

通过覆盖您的persons指针,您会在分配的存储中丢失手柄。因此,在您这样做之前,您必须致电

::operator delete(persons[0].pets);
::operator delete(persons[1].pets);
::operator delete(persons);

这很丑陋,不是吗?因此,存在std::vector容器。

#include <vector>
struct Person {
  std::vector< Pet > pets;
};
std::vector< Person > persons(2);
persons[0].pets = std::vector< Pet >(2);
persons[1].pets = std::vector< Pet >(3);
persons = std::vector< Person >(3); // won't lose memory

由于您可能没有听说过,我建议您在RAII或这里阅读。

简而言之,不,您需要删除它们。

您创建的第一人称阵列将成为垃圾,因此在将另一个数组分配给指针之前,您应该将其删除(免费)。(将"新"操作员视为访问内存位置的请求权限(键),因此,如果您丢失了该位置的地址,您将无法再使用它,也不会再使用它(因为您有钥匙!),因此变成垃圾。)

现在,如果您删除了该阵列,您仍然将宠物阵列作为垃圾,因此您应该先删除它们(否则您没有其地址,再一次,又是垃圾!),然后删除人阵列。

更好的(和标准)方法是为人编写攻击方法,并删除其中的宠物阵列。当一个人对象被删除时,将自动调用破坏者。