mercredi 25 novembre 2015

GCC and Clang give thumbs up - Visual Studio trips. Logic error?

Couldn't break this into a smaller example... So I'm using an std::multimap to store some values... It's a simple polynomial class.

The problem is the last function, which multiplies two polynomials. As it multiplies them, it produces a polynomial with multiple terms, which can be summed together (2x^2 + 3x^2 => 5x^2).

So I try to do that and Visual Studio complains (Debug Assertion Failed! Expression: map/set iterator not dereferencable). Tested and worked fine with Clang and GCC. Also, it works perfectly with Visual Studio in Release mode, so I thought this might be an error on my part or something with the logic! So my question is this: is the following code valid and correct? If not, how should I go about improving it? Don't comment too much on the other parts, please.

#include <iostream>
#include <cstddef>
#include <map>
#include <iterator>
#include <initializer_list>

//DIRTY YET SO BEAUTIFUL HACK       //don't judge the macro :P
#define EXPAND_PACK(FUN) \
        using type = int[]; \
        type{ 0, ((FUN), void(), 0)... }

template<class T>
class polynomial
{
private:
    struct _custom_compare //for std::multimap to sort properly
    {
        bool operator()(const std::size_t& a, const std::size_t& b) const
        {
            return a > b;
        }
    };

private:
    std::multimap<std::size_t, T, _custom_compare> _data;

public:
    template<class... Args>
    polynomial(Args&&... pack)
    {
        std::size_t power = sizeof...(pack)-1;

        EXPAND_PACK(_data.emplace(power--, pack));
    }

    auto operator*(const polynomial &rhs) const { return _multiply(rhs); }

    friend std::ostream& operator<<(std::ostream& os, const polynomial& poly)
    {
        //implementation of this not important
    }

private:
    auto _multiply(polynomial rhs) const
    {
        polynomial lhs(*this);

        polynomial<decltype((*_data.cbegin()).second + (*rhs._data.cbegin()).second)> ret;

        for (const auto& i : lhs._data)
        {
            for (const auto& j : rhs._data)
                ret._data.emplace(i.first + j.first, i.second * j.second);
        }

        decltype(ret) new_ret;
        std::size_t power = (*ret._data.cbegin()).first;

        decltype((*ret._data.cbegin()).second + (*ret._data.begin()).second) sum = 0;

        //POINT OF INTEREST HERE!!
        for (auto i = ret._data.cbegin(); i != ret._data.cend(); )
        {
            while ((*i).first == power)
            {
                sum += (*i).second;
                ++i;
            }

            new_ret._data.emplace(power, sum);
            sum = 0;
            --power;
        }

        return new_ret;
    }
};

int main()
{
    polynomial<int> p(3, 4);
    polynomial<int> p2(5, 8, 4);

    std::cout << p * p2;
}

Aucun commentaire:

Enregistrer un commentaire