现在我使用gm:s引擎制作了几年的游戏(我向你保证我不会使用拖放的新手,就像往常一样),我决定开始学会自己使用c ++,你知道扩展我的知识和所有好东西= D
在执行此操作时,我一直在尝试将列表类作为练习项目,您知道,有一组节点链接在一起,然后循环抛出这些节点以获取索引的值,这里是我的代码,我问,因为代码有一个我很难理解的主要问题
template<class type>
class ListNode
{
public:
type content;
ListNode<type>* next;
ListNode<type>* prev;
ListNode(type content) : content(content), next(NULL), prev(NULL) {}
protected:
private:
};
template<class type>
class List
{
public:
List() : SIZE(0), start(NULL), last(NULL) {}
unsigned int Add(type value)
{
if (this->SIZE == 0)
{
ListNode<type> a(value);
this->start = &a;
this->last = &a;
}
else
{
ListNode<type> a(value);
this->last->next = &a;
a.prev = this->last;
this->last = &a;
}
this->SIZE++;
return (this->SIZE - 1);
}
type Find(unsigned int pos)
{
ListNode<type>* a = this->start;
for(unsigned int i = 0; i<this->SIZE; i++)
{
if (i < pos)
{
a = a->next;
continue;
}
else
{
return (*a).content;
}
continue;
}
}
protected:
private:
unsigned int SIZE;
ListNode<type>* start;
ListNode<type>* last;
};
无论如何,至少对我而言,这段代码看起来很好,并且它的工作原理是我能够创建一个新的列表而不会崩溃,并且能够将元素添加到此列表中,并返回正确的索引然而,除了从列表本身获取元素的值时出现问题,就像我运行以下测试代码时,它没有给我构建它给我的内容< / p>
List<int> a;
unsigned int b = a.Add(313);
unsigned int c = a.Add(433);
print<unsigned int>(b);
print<int>(a.Find(b));
print<unsigned int>(c);
print<int>(a.Find(c));
现在这个代码我希望能给我
0
313
1
433
因为那被告知要做什么,然而,只有一半这样做,给我
0
2686684
1
2686584
现在,我处于迷失状态,我认为提供的值是某种指针地址,但我根本不理解那些意图是什么,或者是什么导致价值成为那,或为什么
因此我问互联网,wtf导致这些值被给出,因为我在这一点上很困惑
我道歉,如果这有点漫长而漫无目的,我倾向于经常写这样的东西= D
thanks = D
答案 0 :(得分:8)
当您存储指向局部变量的指针并稍后取消引用这些指针时,代码中有很多undefined behaviors。一旦声明的范围结束,局部变量就会被破坏。
示例:
if (this->SIZE == 0)
{
ListNode<type> a(value);
this->start = &a;
this->last = &a;
}
一旦达到右括号,if
主体的范围就会结束,变量a
将被破坏。指向此变量的指针现在是一个所谓的散列指针,并以任何方式使用它将导致未定义的行为。
解决方案是使用new
动态分配对象:
auto* a = new ListNode<type>(value);
或者如果您没有支持C ++ 11的编译器
ListNode<type>* a = new ListNode<type>(value);
答案 1 :(得分:0)
第一个建议:使用valgrind或类似的内存检查程序来执行此程序。您可能会发现由于解除引用超出范围的堆栈指针而导致许多内存错误。
第二个建议:了解堆栈上的对象与堆上的对象之间的区别。 (提示:你想在这里使用堆对象。)
第三个建议:了解&#34;所有权&#34;指针。通常,您希望非常清楚应该使用哪个指针变量来删除对象。执行此操作的最佳方法是使用std::unique_ptr
智能指针。例如,您可以决定每个ListNode是否由其前任拥有:
std::unique_ptr<ListNode<type>> next;
ListNode<type>* prev;
并且List容器拥有列表的头节点
std::unique_ptr<ListNode<type>> start;
ListNode<type>* last;
这样编译器将在编译时为您完成大量工作,并且您不必非常依赖于在运行时使用valgrind。