dimanche 24 janvier 2016

Why does realloc() fail in this program?

Why does realloc() fail in this program with message *** glibc detected *** ./main.out: realloc(): invalid next size: [address(not null)] *** The result of the program is

0
Realloc BEGIN
Realloc SIZE 4 ADDR 0
Realloc END
Emplace BEGIN
Emplace END
!
4
Emplace BEGIN
Emplace END
!
4
Emplace BEGIN
Emplace END
!
4
Emplace BEGIN
Emplace END
!
4
Realloc BEGIN
Realloc SIZE 10 ADDR 0x1123240
#include <iostream>

#include <cstdlib>
#include <new>

template<class T, class... Args>
class FastFunc;

template<class T, class... Args>
class FastFunc<T(Args...)>{
public:

    template<class F>
    FastFunc(F&& f) : 
        fobj_(new F(static_cast<F&&>(f))),
        caller_(static_cast<Caller>([](void* f, Args&&... args) -> void {
            (*reinterpret_cast<F*>(f))(static_cast<Args&&>(args)...);
        })),
        deleter_(static_cast<Deleter>([](void* f) -> void {
            delete reinterpret_cast<F*>(f); 
        }))
    {  }

    ~FastFunc()
    {
        deleter_(fobj_);
    }

    T operator()(Args&&... args) const
    {
        return caller_(fobj_, static_cast<Args&&>(args)...);
    }

private:

    typedef T(*Caller)(void*, Args&&...);
    typedef void(*Deleter)(void*);

    void* fobj_;
    Caller caller_;
    Deleter deleter_;

};

template<class T>
class Lazy {
public:

    Lazy(T&& val) noexcept : 
        val_(static_cast<T&&>(val)),
        chain_(nullptr),
        cap_(0u),
        size_(0u)
    {  }

    ~Lazy()
    {
        void(get());
        free(chain_);
    }

    template<class F>
    void chain(F&& f)
    {
        if(size_ + 1 > cap_) {
            std::cout << "Realloc BEGIN" << std::endl;
            cap_ = (cap_ * 16) / 10 + 4;
            std::cout << "Realloc SIZE " << cap_ << " ADDR " << chain_ << std::endl;
            Chain* new_mem = reinterpret_cast<Chain*>(realloc(chain_, cap_));
            if(new_mem != nullptr) {
                chain_ = new_mem;
            } else {
                throw std::bad_alloc();
            }
            std::cout << "Realloc END" << std::endl;
        }
        std::cout << "Emplace BEGIN" << std::endl;
        new (&chain_[size_++]) Chain(static_cast<F&&>(f));
        std::cout << "Emplace END" << std::endl;
        std::cout << '!' << std::endl;
    }

    T& get()
    {
        const Chain* const end = &chain_[size_];
        const Chain* it = chain_;

        while(it != end) {
            (*it)(val_);
            it->~Chain();
            ++it;
        }

        size_ = 0u;

        return val_;
    }

    template<class F>
    Lazy<T>& operator+=(F&& f)
    {
        chain(static_cast<F&&>(f));
        return *this;
    }

    T& operator*()
    {
        return get();
    }    

public:

    typedef FastFunc<void(T&)> Chain;

    T val_;    
    Chain* chain_;
    size_t cap_;
    size_t size_;

};

int main()
{   
    Lazy<int> li (10);

    for(int i = 0; i < 5; ++i) {
        std::cout << li.cap_ << std::endl;
        li.chain([](int& x) { x = x * x * x; });
    }

    std::cout << *li << std::endl;
}

Aucun commentaire:

Enregistrer un commentaire