1

簡単に言うと、テンプレートの二重リンク リストを作成しましたが、リストを他のリスト内に配置すると問題が発生します。この質問は解決されました。

Double-Linked-Lists をテンプレートとしてテストしていますが、別のリンク リスト内にリンク リストを配置すると、次のエラーが発生するという問題が発生しています。

(Microsoft Visual Studio 2010 Express)

Windows は、linkListTesting.exe でブレークポイントをトリガーしました。これは、linkListTesting.exe またはそれがロードした DLL のバグを示す、ヒープの破損が原因である可能性があります。これは、linkListTesting.exe にフォーカスがあるときにユーザーが F12 キーを押したことが原因である可能性もあります。出力ウィンドウには、より多くの診断情報が表示される場合があります。

この特定のエラーを検索すると、「初期化されていない変数を使用しないようにしてください」という行に沿った結果が得られました。このシナリオでは、リストに push_back / push_front などを指示すると、リストが初期化されます。(F12を押さないので、そのシナリオはアウトです。)

これが私のメインのcppです->

#include "vcLLMK2.h"

int main(int argc, char *argv[])
{
    vcList<vcList<int>> a;
    vcList<int> b;
    b.push_back(1);
    a.push_back(b);
    //ERROR HAPPENS HERE APPARENTLY
    return 0;
}

新しいエントリ (この場合は '1') を 'b' にプッシュ バック (またはフロント、それも試してみました) するとうまくいきます。クラッシュも愚かさもありません。「b」を「a」にプッシュすると、アプリケーションは前述のエラーを吐き出し、ブレークポイントをトリガーして終了します。

私は最近 SDL をいじり始めました。リストを 16 層のコンテナとして使用するつもりです。これは基本的にレンダリングするスプライト/タイル/その他のリストです。考え方としては、プログラムはレイヤーを含むリスト内の各エントリを反復処理し、含まれるレイヤー内の各オブジェクトをレンダリングしてから次のレイヤーに移動するというものです。

「なぜ std::list を使わないのですか?」-浮気だから.

このスレッドで答えてくれる人は、私のリストの構造と実装における、私が幸いなことに気づいていない明らかな欠陥のそれぞれを指摘できる可能性が高いですが、私が最も心配しているのは、特にこの奇妙なエラーの原因とその修復方法。そうは言っても、皆さんへの私の質問は、上記の cpp が実行時にエラーになる原因となる、私が構築したリンクリストのセットアップの何が問題なのですか?

以下のリンクされたリストの構造は、次のページを読んだ集大成
です
。 /tutorial/lesson15.html
http://geekswithblogs.net/MarkPearl/archive/2010/02/20/linked-lists-in-c.aspx
テンプレートに変換することは、主にこのページの創造的な解釈の結果です:
http ://www.cplusplus.com/doc/tutorial/templates/

これが私のLink-Listテンプレートクラスで、コメントがたくさんあります->

#pragma once
#ifndef vcLLMK2_H_INCLUDED
#define vcLLMK2_H_INCLUDED
#define NULL 0

//THIS IS ALL OUR NODE SHOULD EVER NEED
template <class T>
struct vcListNode
{
    public:
    T data;
    vcListNode<T> *next;
    vcListNode<T> *prev;
};

template <class T>
struct vcList
{
    public:
    vcListNode<T> *root;//the list's "start"
    vcListNode<T> *end;//the list's "end"
    vcListNode<T> *cur;//used to bounce around amongst entries

    int size();//returns number of non-null entries
    int count;//because keeping track of these is easier than iterating through every time

    void setAt(T,int);//sets data in a node
    void push_front(T);//inserts a new node at the beginning of the list
    void push_back(T);//same thing but back of list
    void removeAt(int);//kills a node at an arbitrary spot in the list
    void clear();//deletes all of the nodes in the list
    T getAt(int);//returns data from a node in the list
    vcList<T>& operator = (const vcList<T>&);//used for setting list a's contents to list b
    //EDIT COPYCONSTRUCTOR
    vcList<T>(const vcList<T>&);//copyconstructor

    vcList();// : root(NULL),end(root),cur(NULL),count(0){};
    ~vcList();
};

//constructor - sets everything to null and count to zero on init
template <class T>
vcList<T>::vcList()
{
    root=NULL;
    cur=NULL;
    end=NULL;
    count=0;
}

//destructor - deletes all nodes
template <class T>
vcList<T>::~vcList()
{
    clear();
}

//deletes all nodes from root to end
template <class T>
void vcList<T>::clear()
{
    if(root==NULL)//assume list has nothing in it, abort
    return;

    //set current targeted entry to root
    cur = root;
    //as long as we have somewhere to go...
    while(cur->next!=NULL)
    {
        //go there
        cur=cur->next;
        //and destroy where we were
        delete cur->prev;
    }
    //then destroy ourselves because nihilism is good for memory
    delete cur;
}

//used to set the contents of a list equal to those of another
template <class T>
vcList<T>& vcList<T>::operator= (const vcList<T> &fays)
{
    //for starters, clear ourselves of any unwanted garbagedata
    clear();

    //check the import list's root entry
    cur = fays.root;

    //if the list containing the values we are importing is empty, we're done, move along
    if(cur==NULL)
    return *this;

    //otherwise, make a new node - it's our new root
    vcListNode<T> *newEntry = new vcListNode<T>;
    newEntry->data = fays.root->data;
    newEntry->prev = NULL;
    newEntry->next = NULL;
    //set root/end to the new entry
    root = newEntry;
    end = newEntry;
    //update our count
    count=1;

    //fire through the import-list's entries
    //cur starts at root
    while(cur->next!=NULL)//(count<fays.count)
    {
        //move to next entry
        cur=cur->next;
        //add it to our list, push_back should update the location of 'end' for us
        push_back(cur->data);
    }
    //we should be done here, so go ahead and return everything
    return *this;
}

//this is mostly for convenience
template <class T>
int vcList<T>::size()
{
    return count;
}

//adds a new entry to the front of our linked list
template <class T> 
void vcList<T>::push_front(T info)
{
    //eat some memory
    vcListNode<T> *newEntry;
    newEntry = new vcListNode<T>;

    //set our memory and all that neat stuff
    newEntry->data = info;
    newEntry->next = root;
    newEntry->prev = NULL;

    //if our linked list is not empty
    if(root!=NULL)
        //set root's previous link to point at our new entry
        root->prev = newEntry;

    //if our linked list does not have an assigned end yet
    if(end==NULL)
        //assume it's empty and set end to our entry
        end=newEntry;

    //update the position of our root in the list, the beginning now begins at the beginning again
    root = newEntry;

    //and since we added something to the list, we should probably update our count of things in the list
    count++;
}

//this finds an element in the pointer-chain and sets its information
template <class T> 
void vcList<T>::setAt(T info,int index)
{
    //set our target to the root
    cur=root;

    //run through the list's entries until we're where we're supposed to be
    while(index>0)
    {
        cur=cur->next;
        index--;
    }

    //set the data in the cell/node/whatever to our input
    cur->data=info;
}

//returns the data contained in a node at a position in the list
template <class T> 
T vcList<T>::getAt(int meBro)
{
    //set target to root
    cur=root;
    //progress through the list
    while(meBro>0)
    {
        cur=cur->next;
        meBro--;
    }
    //dig the data out of the entry and return it
    return cur->data;
}

//adds an element-containing node to the end of the list-chain
template <class T> 
void vcList<T>::push_back(T info)
{
    //if our list already has entries, end shouldn't be null
    if(end!=NULL)
    //so just target our end slot
    cur=end;

    //if our list is empty, however
    else
        //target the root instead
        cur=root;

    //create our new node, put stuff in it, etc
    vcListNode<T> *newEntry;
    newEntry = new vcListNode<T>;
    newEntry->data = info;
    //we're adding to the END of the list so make next null
    newEntry->next = NULL;

    //if cur is NOT null, then theoretically we're pointed at the end of the list
    if(cur!=NULL)
        //set our new entry's previous pointer to the end
        newEntry->prev = cur;

    //cur IS null, which means the list is empty
    else
        //set our entry's previous pointer to be null, duh
        newEntry->prev = NULL;

    //if the end of our list exists
    if(end!=NULL)
    {
        //set the next entry in the list to point at our new entry
        end->next = newEntry;
        //then set end to target the new entry
        end=newEntry;
    }
    //and if our list does not have an end yet for some reason (read as: it's empty)
    else
    {
        //set the root to our new entry
        root = newEntry;
        //set the end to our new entry as well, since there's only one entry in the list
        end = newEntry;
    }

    //update count of number of objects in list
    count++;
}

//this deletes/removes/destroys/obliterates a node at a location in the list
template <class T> 
void vcList<T>::removeAt(int index)
{
    //for starters - is what we're trying to kill even here?
    if(index>=count)
        //NOPE GET OUT
        return;

    //later on it might speed things up to check whether the distance from end or root is shorter
    //for now, just start at the beginning

    //target the root
    cur=root;

    //move through the list to the specified entry
    while(index>0)
    {
        index--;
        cur=cur->next;
    }

    //if the previous entry exists
    if(cur->prev!=NULL)
        //point its next at the entry after this one
        cur->prev->next=cur->next;

    //if the previous entry is NULL, it means we're at the root
    //so tell root to scoot forward one entry
    //if there's a forward to scoot to
    else if(cur->next != NULL)
    root = cur->next;

    //if the next entry exists
    if(cur->next!=NULL)
        //set the next entry's previous pointer to point at the entry before the targeted one
        cur->next->prev=cur->prev;

    //if the next entry does not exist, we must be at the end of the list
    //so tell the end of the list to scoot back one slot
    //if there's a back-one-slot to go to
    else if(cur->prev!=NULL)
    end = cur->prev;

    //remove the entry at the targeted location
    delete cur;

    //decrement our count
    count--;
}
//EDIT -> Copy Constructor
//copy constructor, similar as suggested to the operator=
template <class T>
vcList<T>::vcList(const vcList<T>& fays)
{
    //might not be completely necessary, but we're not hurting anything by making sure
    clear();

//check the import list's root entry
cur = fays.root;

    //if the list containing the values we are importing is empty, we're done, move along
    if(cur==NULL)
    return;//just return, constructors don't get return types

    //otherwise, make a new node - it's our new root
    vcListNode<T> *newEntry = new vcListNode<T>;
    newEntry->data = fays.root->data;
    newEntry->prev = NULL;
    newEntry->next = NULL;
    //set root/end to the new entry
    root = newEntry;
    end = newEntry;
    //update our count
    count=1;

    //fire through the import-list's entries
    //cur starts at root
    while(cur->next!=NULL)//(count<fays.count)
    {
        //move to next entry
        cur=cur->next;
        //add it to our list, push_back should update the location of 'end' for us
        push_back(cur->data);
    }
    //we should be done here, so go ahead and return everything
    //return *this;
}
#endif
4

1 に答える 1

1

C++ で最も重要な概念の 1 つである、参照渡しという概念を確認する必要があると思います。info という名前の引数としての push_back メソッド。これは、メソッドの呼び出しに使用しているオブジェクトのコピーです。vsList オブジェクトのコピーを作成する方法を明示的にコンパイラに指示しなかったため、コンパイラはデフォルトのコピー コンストラクタを作成しますが、意図したとおりに動作しません。

したがって、オブジェクト「a」に格納されているオブジェクトのデストラクタが呼び出されると、コードの問題が実際に発生します。有効なポインターがないため、クラッシュします。push_back (および他のすべてのメソッド) を変更して、値ではなく "const 参照" で T を受け取るか、コピー コンストラクターを実装することで、問題を解決できます。

于 2012-10-30T23:17:04.080 に答える