Исполняемый файл C ++ зависает во время выполнения - PullRequest
1 голос
/ 30 октября 2010

Я написал простую консольную программу для тестирования некоторых ключевых классов в библиотеке, которую я строю.Теперь код собирается правильно, без ошибок.Но после выполнения кода я обнаружил, что приложение перестает работать после вызова метода Index в определенной точке кода.Я попытался отладить несколько разных способов, чтобы получить больше информации о проблеме, но информация, которую я собрал, мне не помогла.Может быть, это поможет кому-то еще, кто знает, что я не делаю (или делаю неправильно).

Вот содержимое пространства имен Util;

    template<typename var>
class VectorNode
{
    public:
    VectorNode(var value, VectorNode<var>* next = NULL, VectorNode<var>* prev = NULL)
    {
        data = value;
        t_next = next;
        t_prev = prev;
    }
    ~VectorNode()
    {
        if (t_next != NULL)
            delete t_next;
    }


    virtual VectorNode<var>* Next(){ return t_next; } // get the next node in line
    virtual void Next(VectorNode<var>* newNode){ t_next = newNode; } // set the next node in line

    virtual VectorNode<var>* Prev(){ return t_prev; }// get the previous node in line
    virtual void Prev(VectorNode<var>* newNode){ t_prev = newNode; } // set the previous node in line

    virtual var Value(){ return data; } // get the node's value

    private:
    var data;
    VectorNode<var>* t_next;
    VectorNode<var>* t_prev;
};

template<typename var>
class Vector
{
    public:
    Vector()
    {
        tailNode = new VectorNode<var>(*(new var));
        headNode = new VectorNode<var>(*(new var), tailNode);
        tailNode->Prev(headNode);
        size = new int;
        *size = 0;
    }
    ~Vector()
    {
        delete headNode;
        delete size;
    }


    int Size(){ return *size; } // get the size of a vector
    void Add(var toAdd, int index = 0) // 
    {
        VectorNode<var>* lastNode;
        if (index > (*size))
            index = *size;
        if (index < 1) // add to the end of the vector
        {
            lastNode = tailNode;
        }
        else
        {
            int i;
            if (index <= (*size / 2)) // if the index is less than half the size, iterate forwards
            {
                lastNode = headNode;
                for (i = 1; i <= index; i++){ lastNode = lastNode->Next(); }
            }
            else // otherwise, iterate backwards
            {
                lastNode = tailNode;
                for (i = *size; i >= index; i--){ lastNode = lastNode->Prev(); }
            }
        }
        VectorNode<var>* temp = lastNode->Prev();
        VectorNode<var>* newNode = new VectorNode<var>(toAdd, lastNode, temp);
        lastNode->Prev(newNode);
        temp->Next(newNode);
        *size = *size + 1;
    }
    void Remove(int index) // remove an index
    {
        VectorNode<var>* toRemove;
        VectorNode<var>* lastNode;
        int i;
        if ((index > *size) || (index < 1)) // if not in the domain...
            index = *size;
        if (index <= (*size / 2)) // iterate forwards
        {
            lastNode = headNode;
            for (i = 1; i < index+2; i++){ lastNode = lastNode->Next(); }
        }
        else // iterate backwards
        {
            lastNode = tailNode;
            for (i = *size; i > index; i--){ lastNode = lastNode->Prev(); }
        }
        toRemove = lastNode->Prev();
        VectorNode<var>* temp = toRemove->Prev();
        temp->Next(lastNode);
        lastNode->Prev(temp);
        delete toRemove;
        *size = *size - 1;
    }
    var Index(int index) // get the value of a node
    {
        VectorNode<var>* lastNode;
        int i;
        if (index <= (*size / 2)) // iterate forwards
        {
            lastNode = headNode;
            for (i = 1; i <= index; i++){ lastNode = lastNode->Next(); }
        }
        else // iterate backwards
        {
            lastNode = tailNode;
            for (i = *size; i >= index; i--){ lastNode = lastNode->Prev();}
        }
        return lastNode->Value();
    }

    private:
    int* size;
    VectorNode<var>* tailNode; // the head and tail nodes are placeholders, to keep the list inside its boundaries
    VectorNode<var>* headNode;
};

Если вы не хотитепрочитав это, я пометил каждый метод комментарием, объясняя его общую цель.Кроме того, я попытался добавить небольшое объяснение некоторых своих блоков кода.

И вот функция ввода и включения;

<pre>#include "iostream"</p> <pre>#include "stdlib.h" // this has nothing in it that's being used</pre> <pre>#include "testhead.h" // the location of the Util namespace</pre> <p>int main() { using namespace Util;</p> <pre><code>Vector<int>* x = new Vector<int>(); x->Add(42); x->Add(24); x->Add(12); x->Add(21); std::cout << "Listing Indices\n"; for (int i = 1; i <= x->Size(); i++) { std::cout << i << "\t" << x->Index(i) << "\n"; } std::cout << "Size(pre-removal):\t" << x->Size() << "\n"; x->Remove(2); std::cout << "Size(post-removal):\t" << x->Size() << "\n"; std::cout << "Listing Indices\n"; std::cout << 3 << "\t" << x->Index(3) << "\n"; for (int i = 1; i <= x->Size(); i++) { std::cout << i << "\t" << x->Index(i) << "\n"; } system("Pause");

}

Хорошо, результаты, которые я получил, где это.Перед использованием метода Remove доступ к любому индексу можно получить из класса Vector.Но, после использования метода remove, независимо от того, какой индекс удален, доступ к индексу выше единицы невозможен.За исключением случая, когда мы удаляем первый индекс, тогда никакие индексы не могут быть доступны.Я попытался пошагово пройти по коду, но он привел меня к этой строке кода в методе index;

else
{
lastNode = tailNode;
for (i = *size; i >= index; i--){ lastNode = lastNode->Prev();} // error occurs after running this line
}

Теперь, когда я смог понять, что метод Remove вызывает проблему, я пошелназад и получил некоторый вывод об этом.Я должен был выполнить следующую строку до завершения выполнения, дважды.Один раз перед удалением toRemove и еще раз после его удаления.

std::cout << (lastNode->Prev() == temp) << "\t" << (temp->Next() == lastNode) << "\n";

Перед удалением он печатает 1 дважды, указывая, что сравнение было истинным.Но во второй раз я вызываю метод Prev и Next, и программа зависает.Я знаю, что это потому, что я освободил место в памяти, но сравнение показывает, что все ссылки с других узлов на удаленный мной узел исчезли.Теперь мой конкретный вопрос: почему именно это вызывается, и как я могу это исправить?Я немного знаю об управлении памятью в куче, и это не совсем похоже на то, как если бы это вызвало какие-либо проблемы с программой.Итак, я мог бы использовать краткое объяснение того, почему это происходит, если кто-то будет любезен предоставить его.

Если это поможет, я использую IDE Code :: Blocks и компилятор GNU GCC.Также, пожалуйста, скажите мне, если я делаю что-то неправильно, в связи с тем, как я задал вопрос.Я не часто бываю в Stack Overflow и не задаю здесь вопросов.Это лучшее место, где я могу ответить на ваши вопросы.

Ответы [ 3 ]

2 голосов
/ 30 октября 2010

Деструктор класса VectorNode удаляет указатель объекта на указатель t_next.Вызов delete для указателя toRemove означает, что вызывается деструктор этого объекта VectorNode, а затем следующий, затем следующий и т. Д. И т.д.все объекты, которые приходят после этого.Это приводит к тому, что t_prev tailNode указывает на память, которую вы уже освободили, и затем вы пытаетесь разыменовать эти указатели в вашей функции Index, и это не очень хорошая вещь.

1 голос
/ 30 октября 2010

Вызов удалить удаляет узел, но удаление узла удаляет все узлы-> следующий

~VectorNode()
{
    if (t_next != NULL)
        delete t_next;
}

, поэтому удаление элемента 2 вашего вектора на основе 1 убивает все другие элементы, которые вы испытали, и тамбольше не является элементом 3 для расследования

1 голос
/ 30 октября 2010

Когда вы удаляете VectorNode, чей член t_next указывает на какой-либо другой узел, деструктор VectorNode удалит этот другой узел (который, в свою очередь, может продолжить удаление других узлов).

Когда вы удаляете узел из середины списка с помощью Remove(), t_next этого узла будет указывать на дальнейшие узлы списка.Когда этот узел удален, деструктор также удалит все узлы, следующие за ним в списке.Продолжение использования этого наполовину удаленного списка приведет к возникновению всевозможных проблем.

Другие случайные наблюдения:

  • Почему size a int* вместо нормального int или size_t?Я не вижу никакой причины, по которой это должен быть указатель.
  • new VectorNode<var>(*(new var)) действительно должен быть new VectorNode<var>(var()), чтобы не допустить ненужной утечки памяти.не требуется
  • Планируете ли вы создавать классы, основанные на VectorNode<>?Если нет, то нет причины, по которой методы должны быть virtual.
  • Использование индексации на основе 1 в Add() является необычным, можно ожидать индексации на основе нуля

Также я вынужден сообщить вам, что существуют стандартные библиотечные контейнеры, такие как std::list<> и std::vector<>, которые реализуют подобные структуры.

...