当我使用VS 2015进入调试模式下的函数时,出现堆栈溢出错误。以下是确切的消息,以防万一:
TestProgram.exe中0x0000000140D9F018的未处理异常:0xC00000FD:堆栈溢出(参数:0x0000000000000001,0x0000000000213000)。
我输入的功能如下:
void CGUITaskRequest::DecodeAndDeserializeSettings(const std::string& sEncodedSettingsString)
{
auto sDecoded = string_functions::base64_decode(sEncodedSettingsString);
std::stringstream ss(sDecoded);
if (m_eType == ETaskTypes::FILE && m_eSubtype == ETaskSubtypes::OPEN) {
auto pSettings = std::make_shared<CModSettingsFileImport>();
cereal::XMLInputArchive arSettingsObject(ss, pSettings->XML_TAG);
pSettings->load(arSettingsObject);
m_ptrSettings = pSettings;
}
else if (m_eType == ETaskTypes::META && m_eSubtype == ETaskSubtypes::STATUS) {
auto pSettings = std::make_shared<SMetaStatusSettings>();
cereal::XMLInputArchive arSettingsObject(ss, pSettings->XML_TAG); // <- line I comment out to run successfully
pSettings->load(arSettingsObject);
m_ptrSettings = pSettings;
}
}
这是让我感到困惑的地方:
cereal::XMLInputArchive arSettingsObject(ss, pSettings->XML_TAG);
那么不仅堆栈溢出错误消失了,而且函数按预期运行,成功执行了“ if”块(因此它成功创建了“ cereal :: XMLInputArchive”,并从字符串流中加载了它,等等)。在两种情况下(函数运行时,并导致堆栈溢出),都将使用相同的输入参数(约300个字符的base64编码xml)对其进行调用。
因此,以某种方式,当我编译所有未注释的代码时,导致函数的执行/内存分配出了点问题,但是我不明白是什么。
哦,是的,如果有帮助,当我收到堆栈溢出错误时,调用堆栈会放在顶部:
TestProgram.exe!__ chkstk()
除此之外,它看起来与函数成功运行时相同(这也使我认为没有递归)。
[编辑]
在搜索__chkstk()之后,我才发现/阅读了这篇SO文章: What is the purpose of the _chkstk() function?
这让我认为这不是传统的堆栈溢出错误,我在这里请求过多的内存,而是函数中的某些内容试图引用内存中的非法位置,这导致VS报告一个错误。堆栈溢出。但是,我仍然不确定,如果该函数甚至没有执行,为什么/如何发生这种情况,因为该代码块不会运行。
预先感谢您对导致这种行为的原因有任何了解。
我很难过,我缺少关于函数调用的一些基本知识。
答案 0 :(得分:1)
结果是_chkstk()
throws a stack overflow when you have exceeded the declared maximum stack size declared in an .exe build。那你的解决方案呢? Increase it。尽管也可以考虑删除代码中的冗余点:
首先,考虑到输入函数,我们需要确保堆栈上有足够的空间容纳函数的所有局部变量。让我们看看它们是什么:
void CGUITaskRequest::DecodeAndDeserializeSettings(const std::string& sEncodedSettingsString)
{
/* two variables here */
auto sDecoded = string_functions::base64_decode(sEncodedSettingsString);
std::stringstream ss(sDecoded);
if (m_eType == ETaskTypes::FILE && m_eSubtype == ETaskSubtypes::OPEN) {
/* two more variables here */
auto pSettings = std::make_shared<CModSettingsFileImport>();
cereal::XMLInputArchive arSettingsObject(ss, pSettings->XML_TAG);
pSettings->load(arSettingsObject);
m_ptrSettings = pSettings;
}
else if (m_eType == ETaskTypes::META && m_eSubtype == ETaskSubtypes::STATUS) {
/* and a final pair */
auto pSettings = std::make_shared<SMetaStatusSettings>();
cereal::XMLInputArchive arSettingsObject(ss, pSettings->XML_TAG); // <- line I comment out to run successfully
pSettings->load(arSettingsObject);
m_ptrSettings = pSettings;
}
}
现在考虑在开始时在调用堆栈上找到_chkstk()
变量。这意味着该功能allocates a lot of memory!注释掉一个声明可以解决问题,这表明贪婪的记忆元凶。但是,等等,您有两个,而您可以逃避一个意味着合并重复的声明可能会带来好处:
void CGUITaskRequest::DecodeAndDeserializeSettings(const std::string& sEncodedSettingsString)
{
auto sDecoded = string_functions::base64_decode(sEncodedSettingsString);
std::stringstream ss(sDecoded);
/* single declaration*/
cereal::XMLInputArchive arSettingsObject;
if (m_eType == ETaskTypes::FILE && m_eSubtype == ETaskSubtypes::OPEN) {
auto pSettings = std::make_shared<CModSettingsFileImport>();
arSettingsObject = cereal::XMLInputArchive(ss, pSettings->XML_TAG);
pSettings->load(arSettingsObject);
m_ptrSettings = pSettings;
}
else if (m_eType == ETaskTypes::META && m_eSubtype == ETaskSubtypes::STATUS) {
auto pSettings = std::make_shared<SMetaStatusSettings>();
arSettingsObject = cereal::XMLInputArchive(ss, pSettings->XML_TAG); // <- line I comment out to run successfully
pSettings->load(arSettingsObject);
m_ptrSettings = pSettings;
}
}
尽管这会更改arSettingsObject
的作用域,但这不是问题,因为该函数在if / else语句之后终止,并且所有声明它的返回路径都需要它。