Может ли кто-нибудь помочь мне с этим? Я думаю, что есть некоторые проблемы:
this->head->s = new Student(s);
и
this->tail->s = new Student(s);
Но я не могу удалить их, потому что мне нужны эти "Студенты". И есть указатели на «Студенты».
Эта проблема, вероятно, указывает на то, что вам следует перепроектировать вашу программу. В C ++ вы должны выразить семантику владения и уточнить, какие объекты владеют какими ресурсами и отвечают за их очистку. Семантика владения в C ++ выражается через различные типы указателей:
Если определенный, отдельный объект владеет некоторой кучей памяти, вместо использования необработанных указателей и new
и delete
напрямую, используйте std::unique_ptr
. std::unique_ptr
лучше, потому что он передает ваши намерения читателям и использует RAII , чтобы помочь предотвратить утечки памяти.
С другой стороны, если объекту не принадлежит фрагмент памяти, используйте вместо него ссылку или необработанный указатель. (В будущем стандартная библиотека C ++ может получить не обладающий интеллектуальным указателем.)
Если ваша структура данных связанного списка владеет объектами ученика, она должна быть той, которая должна их освободить. В этом случае используйте std::unique_ptr
:
void studentRoll::insertAtTail(const Student &s) {
if (head.get() == nullptr) {
this->head = std::make_unique<Node>();
this->head->next = nullptr;
this->head->s = std::make_unique<Student>(s);
this->tail = &*head; // Get a raw pointer
}
else {
this->tail->next = std::make_unique<Node>();
this->tail = &*this->tail->next; // Get a raw pointer
this->tail->next = nullptr;
this->tail->s = std::make_unique<Student>(s);
}
}
Вместо использования std::unique_ptr
другим вариантом будет просто сделать Student
элементом данных вашего типа Node
. Однако это решение может указывать разные намерения и иметь разные последствия. Например, если вы хотите передать право собственности на объект Student
от объекта Node
куда-то еще, вам следует использовать std::unique_ptr
. Если вы сохраняете объект Student
непосредственно как член, вы можете добиться аналогичного эффекта, вызвав конструктор перемещения Student
, но некоторые семантики все равно будут другими. Например, указатели на Student
будут недействительными. См. https://stackoverflow.com/a/31724938/8887578 для большего сравнения двух подходов.
Если объекты учащихся переживают связанный список, он не должен быть их владельцем, и было бы лучше взять указатель на такой объект, не являющийся владельцем. В этом случае не размещайте новые объекты ученика, а берите указатель из другого места:
void studentRoll::insertAtTail(const Student* s) {
if (head.get() == nullptr) {
this->head = std::make_unique<Node>();
this->head->next = nullptr;
this->head->s = s;
this->tail = &*head;
}
else {
this->tail->next = std::make_unique<Node>();
this->tail = &*this->tail->next;
this->tail->next = nullptr;
this->tail->s = s;
}
}
Я не знаю контекст вашей программы (например, если это школьное упражнение по написанию связанных списков), но в серьезном коде вы должны использовать стандартную библиотеку std::list
вместо того, чтобы создавать свой собственный связанный список. Однако во многих случаях std::vector
(аналог динамически выращенного массива) более подходит, чем связанный список.
Кроме того, вместо предоставления Node
конструктора по умолчанию без параметров и последующего присвоения его s
члена, вы должны передать на него указатель ученика в его конструкторе.