Как решить проблему free(): в tcache 2 обнаружено двойное освобождение make: *** [Makefile:88: test] Прервано (дамп ядраC++

Программы на C++. Форум разработчиков
Ответить Пред. темаСлед. тема
Гость
 Как решить проблему free(): в tcache 2 обнаружено двойное освобождение make: *** [Makefile:88: test] Прервано (дамп ядра

Сообщение Гость »


Я работаю над этим проектом, в котором мне нужно реализовать функции класса двойного связанного списка. Однако, когда я попытался запустить тест функции Assign() на своем терминале, я получил free(): в tcache обнаружено двойное освобождение 2make: *** [Makefile:88: test] Прервано (дамп ядра)

Вот что я уже сделал в своем проекте:

#ifndef MY_DOUBLY_LINKED_LIST_HPP #define MY_DOUBLY_LINKED_LIST_HPP /** * ЗАДАЧА: реализовать DoublyLinkedList, его узел и его итератор! * * Я оставил для вас заполненными некоторые методы, * и заглушил некоторую структуру, чтобы уменьшить сложность. * * Вы можете добавлять или удалять методы по своему усмотрению. * до тех пор, пока вы сможете пройти все модульные тесты. * Хотя, возможно, сделать это будет сложнее. Твой выбор! * * Обратите внимание, что здесь мы находимся внутри пространства имен. * DLL находится внутри пространства имен DoublyLinkedList. * который сам находится внутри пространства имен CPSC131 * Это означает, что если вы захотите позже поиграть со своим классом, * вам нужно будет получить к нему доступ следующим образом: * ::CPSC131::DoublyLinkedList::DoublyLinkedList list; * * Посмотрите в main.cpp и CPP_Tests.cpp примеры использования. * DLL и ваш книжный магазин. Но не волнуйтесь слишком сильно, ведь вы * нужно только реализовать эти классы * (основное и тесты уже сделаны за вас) */ // #include #include #include /** * Пространство имен для нашего класса! */ пространство имен CPSC131 { /** * Пространство имен для хранения всего, что связано с нашей DLL. */ пространство имен DoubleLinkedList { /** * Реализуйте наш класс DoublyLinkedList! */ шаблон класс Дабллинкедлист { публика: /** * Класс узла, представляющий один элемент в нашем связанном списке. */ // TODO: завершить все методы класса класс Узел { публика: /// КТОРЫ Node(): prev_(nullptr), next_(nullptr) {} Узел (элемент T) {} Node(T-элемент, Node* предыдущая, Node* следующая) {} /// Устанавливаем указатель на предыдущий элемент void setPrevious(Node* prev) {prev_ = prev;} /// Устанавливаем указатель на предыдущий элемент void setPrev(Node* prev) {prev_ = prev; } /// Получаем указатель на предыдущий элемент Node* getPrevious() { return prev_; } /// Получаем указатель на предыдущий элемент Node* getPrev() { return prev_; } /// Устанавливаем указатель на следующий узел void setNext (Node* next) { next_ = next; } /// Получаем указатель на следующий узел Node* getNext() { return next_; } /// Устанавливаем элемент, который содержит этот узел void setElement(T element) { this-> element_ = element; } /// Получить элемент, который содержит этот узел /// ДОБРО ПОЖАЛОВАТЬ T& getElement() { return this->element_; } /// Возвращаем ссылку на элемент /// ДОБРО ПОЖАЛОВАТЬ T& оператор*() { return this->element_; } частный: Т элемент_; Узел* предыдущая_; Узел* next_; }; /** * Вложенный класс Iterator. * Это позволяет пользовательскому коду ссылаться на тип Итератора как: * * CPSC131::DoublyLinkedList::DoublyLinkedList::Iterator * * (в отличие от указания аргумента шаблона два раза) */ класс Итератор { публика: ///P-код Итератор(){} ///P-код Итератор(Узел* голова, Узел* хвост): head_(голова), хвост_(хвост) { это->курсор_ = это->конец(); } /// Конструктор, принимающий указатель головы, хвоста и курсора; ДОБРО ПОЖАЛОВАТЬ Итератор(Узел* голова, Узел* хвост, Узел* курсор): head_(голова), хвост_(хвост), курсор_(курсор) {} /// Получаем указатель на головной узел или end(), если этот список пуст Узел* начало() { // TODO: ваш код здесь если (head_ != nullptr) { вернуть голову_; } вернуть нульптр; } /// Получаем указатель узла, представляющий «конец» (он же «истощенный»). Вероятно, вы захотите просто использовать nullptr. Node* end() { return nullptr; } /// Получить узел, на который в данный момент указывает этот итератор Node* getCursor() { return курсор_; } /** * Оператор присваивания * Вернуть копию этого Итератора после модификации. */ Итератор и оператор = (константный итератор и другое) { head_ = другое.head_; хвост_ = другое.хвост_; курсор_ = другой.курсор_; вернуть *это; } /// Оператор сравнения booloperator==(const Iterator&other) { return курсор_==other.cursor_; } /// Оператор сравнения неравенств booloperator!=(const Iterator&other) { return !((*this) ==other);} /** * Оператор увеличения префикса * Вернуть копию этого Итератора после модификации. */ Итератор и оператор++() { // TODO: ваш код здесь если (курсор_ != nullptr) { курсор_ = курсор_ -> getNext(); } вернуть *это; } /** * Приращение постфикса * Вернуть копию этого Итератора ДО того, как он был изменен. */ Оператор итератора++(int) { Итератор temp = *this; если (курсор_ != nullptr) { курсор_ = курсор_ -> getNext(); } температура возврата; } /** * Оператор уменьшения префикса * Вернуть копию этого Итератора после модификации. */ Итератор и оператор --() { // TODO: ваш код здесь если (курсор_ != nullptr) { курсор_ = курсор_ -> getPrev(); } вернуть *это; } /** * Постфиксный оператор декремента * Верните копию этого итератора ДО того, как он был изменен. */ Оператор итератора -- (int) { // TODO: ваш код здесь если (курсор_ != nullptr) { Температура итератора (head_, Tail_, курсор_); курсор_ = курсор_ -> getPrev(); температура возврата; } вернуть *это; } /** * Оператор AdditionAssignment. * Возвращает копию текущего итератора после модификации */ Оператор итератора +=(size_t add) { // TODO: ваш код здесь курсор_ += добавить; вернуть *это; } /** * Оператор вычитанияприсваивания * Возвращает копию текущего итератора после модификации */ Оператор итератора -=(size_t add) { // TODO: ваш код здесь курсор_ -= добавить; вернуть *это; } /** * Оператор AdditionAssignment, поддерживающий положительные или отрицательные целые числа. */ Оператор итератора +=(int add) { // TODO: ваш код здесь while (cursor_ != nullptr && add != 0) { если (добавить > 0) { for(int я = 0; я end(), вставьте элемент в хвост. * * Должен возвращать итератор, указывающий на вновь добавленный узел * * Чтобы избежать повторения кода, было бы неплохо иметь другие методы. * полагаться на это. */ Итератор Insert_after (Итератор pos, константное значение T&) { // TODO: ваш код здесь // вернуть Итератор(); } /** * Вставьте новый элемент после индекса поз. * Должно работать с пустым списком. * * Должен возвращать итератор, указывающий на вновь созданный узел * * Чтобы уменьшить количество повторяющегося кода, вы можете просто найти * итератор узла с индексом позиции, затем * отправить его в другую перегрузку этого метода. */ Итератор Insert_after(size_t pos, const T& ценить) { // TODO: ваш код здесь вернуть Итератор(); } /** * Сотрите узел, на который указывает курсор Итератора. * * Если итератор 'pos' не указывает на действительный узел, * выдать std::range_error * * Возвращаем итератор узлу ПОСЛЕ того, который мы удалили, * или this->end(), если мы только что удалили хвост */ Стирание итератора (Итератор pos) { // TODO: ваш код здесь вернуть Итератор(); } /** * Добавьте элемент сразу после элемента, на который указывает итератор 'pos'. * * Должен возвращать итератор, указывающий на вновь созданный узел */ Итератор push_after (Итератор pos, константное значение T&) { // TODO: ваш код здесь // вернуть Итератор(); } /** * Добавьте новый элемент в начало нашего списка. */ void push_front (значение const T&) { // TODO: ваш код здесь } /** * Добавьте элемент в конец этого списка. * * Должен возвращать итератор, указывающий на вновь созданный узел. */ Итератор push_back (значение const T&) { //TODO: ваш код здесь Узел* newNode = новый Узел(значение); если (пусто ()) { head_ = новыйузел; хвост_ = новыйузел; } newNode -> setPrev(tail_); Tail_ -> setNext(newNode); хвост_ = новыйузел; размер_++; вернуть последний(); } /** * Удалите узел в начале нашего списка. * * Должен выдать исключение, если наш список пуст */ недействительный pop_front() { // TODO: ваш код здесь } /** * Удаляем узел в конце нашего списка * * Должен выдать исключение, если наш список пуст */ недействительный pop_back() { // TODO: ваш код здесь } /** * Вернуть ссылку на элемент спереди. * * Выдать исключение, если список пуст. */ Т& фронт() { // TODO: ваш код здесь если (пусто ()) { throw std::range_error("Список пуст"); } вернуть head_->getElement(); } /** * Вернуть ссылку на элемент сзади. * * Выдать исключение, если список пуст. */ Т& назад() { // TODO: ваш код здесь если (пусто ()) { throw std::range_error("Список пуст"); } вернуть хвост_->getElement(); } /** * Возвращает элемент по индексу * * Должно выдаваться сообщение об ошибке range_error, выходящее за пределы. */ Т& в (индекс size_t) { // TODO: ваш код здесь если (пусто ()) { throw std::range_error("Пустой список"); } иначе если (индекс >= size_ ) { throw std::range_error("Индекс выходит за пределы"); } Узел* ток = head_; size_t я = 0; в то время как (я < индекс) { текущий = текущий->getNext(); я++; } вернуть текущий->getElement(); } /** * Обратный текущий список * * Возможно, было бы легко рассмотреть следующее: * - Создать временный пустой список * - Перебор текущего списка * - Для каждого элемента текущего списка нажмите ВПЕРЕД (не назад) * - Назначить текущий список временному списку * - Отменить временный список */ недействительный реверс() { // TODO: ваш код здесь } /** * Могу поспорить, ты рад, что я не заставляю тебя это делать. * Никакие тесты для этой функции проводиться не будут. * но не стесняйтесь попробовать это в качестве испытания! * * Если бы я делал это и не слишком заботился об эффективности, * Я бы, вероятно, создал дополнительную вспомогательную функцию, чтобы поменять местами две * позиции в текущем списке. * Тогда я бы просто пролистал список и выполнил * алгоритм пузырьковой сортировки. Возможно сортировка выбором. * * Если вам нужна серьезная задача, попробуйте реализовать быструю сортировку. * * (но опять же, не беспокойтесь об этом методе, он не будет проверен) */ недействительная сортировка() { // TODO: ваш код здесь } /** * Оператор присваивания * * Очистите этот список и заполните его значениями других * (по значению, а не по ссылке) * * Вернуть ссылку на этот список */ Оператор DoublyLinkedList& =(DoublyLinkedList& другое) { // TODO: ваш код здесь вернуть *это; } /** * Возвращает true, если списки «равны» * * «Равный» здесь определяется как: * - Тот же размер * - Элементы с одинаковыми индексами будут возвращать true для своих собственных операторов сравнения. * * Другими словами: «Они содержат одинаковые значения» * (ссылки друг на друга быть не должны) */ логический оператор ==(DoubleLinkedList& другое) { // TODO: ваш код здесь if(size() != Other.size()) { вернуть ложь; throw std::range_error("Размер не тот"); } Итератор head = начать(); Итератор Otherhead = Other.begin(); while(head != end()) { if(*head != *otherhead) { вернуть ложь; } ++голова; ++другая голова; } вернуть истину; } /** * Возвращает true, если списки «не равны». * * См. заглушку оператора== для определения слова "равно". * * Вероятно, вы хотите избежать повторения кода, полагаясь на другого оператора. */ логический оператор !=(DoubleLinkedList& другое) { // TODO: ваш код здесь return !(*это == другое); } частный: Узел* head_ = nullptr; Узел* Tail_ = nullptr; размер_т размер_ = 0; }; } } #endif Когда я закомментировал функцию push_back в методе Assign(), тест можно запустить, но как только я использовал push_back для присвоения значения, я получил ошибку прерванного (сброс ядра)
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «C++»