简体   繁体   中英

Why does this memoized code segfault?

I have the following code that computes the Stirling number of the second kind for a given n and 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;
}

Unfortunately, when this code is running, it segfaults. It seems to run fine for the first 87795 values inserted into memo , but then crashes shortly thereafter. Specifically, the segfault happens at map::count , in the line if (memo.count(nKPair) > 0) { . I thought maybe this was a matter of memo running out of size, so I added the following caveat to the assignment to memo ,

if (memo.size() < memo.max_size()) {
    memo[nKPair] = val;
}

But that didn't help. I've also noticed that the 87795 value is not indicative of when this crashes. With some minor modifications, changing the first if statement to,

if (n <= k) {
    return 1;
}

changes that value to 66453.

Does anyone know what's going on here?

Ok, so after hours of confusion, I narrowed this down to an expression templates issue. I don't really fully understand why, but it all had to do with that little auto in the line

auto val = k * stirlingS2(n - 1, k) + stirlingS2(n - 1, k - 1)

Basically, change that auto to mp::cpp_int and suddenly, no segfault.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM