为啥这个记忆代码段错误?
Posted
技术标签:
【中文标题】为啥这个记忆代码段错误?【英文标题】:Why does this memoized code segfault?为什么这个记忆代码段错误? 【发布时间】:2016-08-08 21:57:09 【问题描述】:我有以下代码计算给定 n 和 k 的第二类斯特林数,
#include <cstdint>
#include <map>
#include <boost/multiprecision/cpp_int.hpp>
namespace mp = boost::multiprecision;
mp::cpp_int stirlingS2(unsigned n, unsigned k)
if (n == 0 && k == 0)
return 1;
if (n == 0 || k == 0)
return 0;
static auto memo = std::map<std::pair<unsigned, unsigned>, mp::cpp_int>();
auto nKPair = std::pair<unsigned, unsigned>(n, k);
if (memo.count(nKPair) > 0)
return memo[nKPair];
auto val = k * stirlingS2(n - 1, k) + stirlingS2(n - 1, k - 1);
memo[nKPair] = val;
return val;
不幸的是,当这段代码运行时,它会出现段错误。插入memo
的前 87795 个值似乎运行良好,但此后不久就崩溃了。具体来说,段错误发生在map::count
,在if (memo.count(nKPair) > 0)
行中。我想这可能是memo
的大小不足的问题,所以我在memo
的分配中添加了以下警告,
if (memo.size() < memo.max_size())
memo[nKPair] = val;
但这并没有帮助。我还注意到 87795 值并不表示何时崩溃。通过一些小的修改,将第一个 if 语句更改为,
if (n <= k)
return 1;
将该值更改为 66453。
有人知道这里发生了什么吗?
【问题讨论】:
你打算在哪里插入一些东西到备忘录中? 你确定段错误在memo.count
行上,而不是由于没有正确记忆而导致通过深度递归炸毁堆栈?
@DavidThomas,如果键不存在,operator[]
不会为键插入新元素吗?
@JordyDickinson 是的,确实如此......但是地图中的所有内容都是默认构造的 cpp_int。这是故意的吗?
你为什么用if (memo.count(nKPair) > 0) return memo[nKPair];
而不是auto it = memo.find(nKPair); if (it != memo.end()) return it.second;
?你在哪里插入地图?
【参考方案1】:
好的,经过数小时的困惑,我将其范围缩小到表达式模板问题。我不太明白为什么,但这一切都与行中的那个小 auto
有关
auto val = k * stirlingS2(n - 1, k) + stirlingS2(n - 1, k - 1)
基本上,将 auto
更改为 mp::cpp_int
,然后突然就没有段错误了。
【讨论】:
以上是关于为啥这个记忆代码段错误?的主要内容,如果未能解决你的问题,请参考以下文章
为啥这段代码在 64 位架构上会出现段错误,但在 32 位上却能正常工作?