在这段代码引发问题之前,调用堆栈可以有多大
How big can call stack be before this code causes trouble?
我优化了链表析构函数,如下所示:
template <class T>
class LinkedList
{
/* snip */
T* pData;
LinkedList* pNext;
};
template <class T>
LinkedList<T>::~LinkedList()
{
delete pData;
delete pNext;
}
现在我有点担心它可能会在大名单上引起麻烦。此代码会导致堆栈溢出吗?如果是,在多大的名单上?
堆栈的大小由许多因素决定,例如系统上的操作系统/编译器/配置设置。
我绝对不会使用递归方法来删除列表中的元素,因为你很可能会溢出堆栈-你可以通过创建一个包含X个元素的列表来尝试,如果有效的话,加倍X,直到达到堆栈溢出-我几乎可以保证它发生在几千个元素内(可能是10-100k,但肯定不会超过这个)。
删除二叉树之类的递归函数更容易被接受,因为(假设合理的平衡)递归级别的数量是log2(n)
,而不是n
,所以在堆栈溢出之前可以有大量的元素。
我选修了你的课程,并将其扩展为"有效"(这可能与你使用它的方式完全不同,但它可以解释问题):
#include <iostream>
using namespace std;
template <class T>
class LinkedList
{
public:
LinkedList() : pNext(0), pData(0) {};
LinkedList(T e) : pNext(0) { pData = new T(e); }
LinkedList(LinkedList* l, T e) : LinkedList(e) { pNext = l;}
LinkedList *AppendFirst(LinkedList *l) { l->pNext = this ; return l; }
LinkedList *Next() { return pNext; }
T Data() { return *pData; }
~LinkedList();
private:
T* pData;
LinkedList* pNext;
};
#if 0
template <class T>
LinkedList<T>::~LinkedList()
{
delete pData;
delete pNext;
};
#else
template <class T>
LinkedList<T>::~LinkedList()
{
LinkedList<T>* p;
LinkedList<T>* q;
p = pNext;
while(p)
{
q = p->pNext; // Save next link.
p->pNext = NULL; // Break the link.
delete p->pData;
p->pData = NULL;
delete p;
p = q;
}
delete pData;
};
#endif
typedef LinkedList<int> IntList;
int main()
{
for(int x = 0; x < 30; x++)
{
cout << "Trying " << (1 << x) << " elements" << endl;
IntList *head = new IntList(-1);
for(int i = 0; i < (1 << x); i++)
{
head = head->AppendFirst(new IntList(i));
}
cout << "Now destroying " << (1 << x) << " elements" << endl;
delete head;
}
}
如果我将#if 0
更改为#if 1
(或其他具有这种效果的东西),它适用于128K元素,并在256K时崩溃。如果我在#else
中使用迭代方法,当它达到268435456(256M个条目)时,我不得不停止它,因为我的机器没有足够的内存,并且开始进行糟糕的交换(我只有16GB的RAM,这不仅仅是这样)。
相关文章:
- Visual Studio(或任何其他工具)能否将地址解释为调用堆栈(boost上下文)的开头
- 为什么调用堆栈数组会导致内存泄漏
- 是否可以检查悬挂光纤的调用堆栈?
- MSVC __debugbreak() 与 openGL 错误回调一起使用时不会产生调用堆栈
- 了解使用堆栈实现队列的递归调用机制
- C++析构函数调用两次,堆栈分配的复合对象
- 以下代码如何工作以每次为唯一调用堆栈唯一实例化模板函数?
- OpenCV 3 Visual Studio 2017 调试,调用堆栈没有.pdb文件
- C/C++中全局调用堆栈的基础
- 是否可以访问代码中的调用堆栈?
- 使用在堆栈上创建的对象调用虚拟函数
- 为什么析构函数无休止地调用自己(导致堆栈溢出)?
- 调用堆栈显示 SIGBUS,这意味着什么
- 堆栈展开如何与析构函数调用有关?
- 打开C++故障转储不会在调用堆栈中显示正确的行
- 防止 CRTP 特征码在"pure virtual"调用中堆栈溢出
- 将参数推送到调用堆栈 (C++) 的可移植方法
- 从基类堆栈调用派生类实例
- 堆栈调用析构函数,即使遵循三规则
- 用于生成函数以从运行时堆栈调用带参数的函数的模板