长话短说:我制作了一个模板双链表,将列表放在其他列表中会导致问题。这个问题已经解决了。
我正在测试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层的容器,基本上是sprite / tiles / etc的列表。思维方式是程序将遍历包含图层的列表中的每个条目,然后渲染包含图层中的每个对象,然后再转到下一个。
“为什么不使用std :: list?” - 因为那是作弊。
虽然很有可能那些在这个帖子中回答的人能够指出我的列表结构和实现中的每个明显的缺陷,我很幸福没有意识到,我最关心的是什么 - 特别是造成这种特殊错误以及如何解决它。也就是说,我对你们的问题是我构建的链接列表设置有什么问题导致上面的cpp在运行时出错?
以下链接列表结构是阅读以下页面的高潮:
http://www.codeproject.com/Articles/26631/Using-C-templates-for-functions-and-operators
http://www.cprogramming.com/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模板类,有很多评论 - &gt;
#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
答案 0 :(得分:1)
我认为你应该看看C ++中最重要的一个概念,即通过引用传递。 push_back方法作为名为info的参数,即用于调用方法的对象的副本。由于您没有明确告诉编译器如何创建vsList对象的副本,因此它将创建一个默认的复制构造函数,但它不能按预期工作。
因此,当调用存储在对象“a”中的对象的析构函数时,代码上的问题确实会发生。由于它没有有效的指针,它会崩溃。您可以通过两种方式解决您的问题,更改push_back(以及所有其他方法)以通过“const reference”而不是通过值或实现复制构造函数来接收T.